Return-Path: Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 19542 invoked from network); 9 Feb 2001 23:20:00 -0000 Received: from nsqw.olliance.com (HELO mail.olliance.com) (63.150.52.11) by h31.sny.collab.net with SMTP; 9 Feb 2001 23:20:00 -0000 Received: from dhcp-100.sfo.lan ([10.1.1.100] helo=olliance.com ident=jason) by mail.olliance.com with esmtp (Exim 3.12 #1 (Debian)) id 14RMpi-0000Z8-00 for ; Fri, 09 Feb 2001 15:20:06 -0800 Message-ID: <3A847BEC.6060608@olliance.com> Date: Fri, 09 Feb 2001 15:23:24 -0800 From: Jason Brittain Organization: Olliance Inc. User-Agent: Mozilla/5.0 (X11; U; Linux 2.2.16-3 i686; en-US; 0.7) Gecko/20010105 X-Accept-Language: en MIME-Version: 1.0 To: tomcat-dev@jakarta.apache.org Subject: [PATCH] TC4: TomcatBlock on Avalon 3.1a1: Part 3 Content-Type: multipart/mixed; boundary="------------050602020409080304080406" X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N --------------050602020409080304080406 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Attached are the files I added to make TomcatBlock (Tomcat 4 running on Avalon 3.1a1): catalina/src/conf/avalon-MANIFEST.MF This manifest file is used to create tomcat-4.0.bar. Avalon needs a special manifest to know which Block is contained in the BAR file. catalina/src/conf/avalon-server.xml When Tomcat runs on Avalon, it needs a special/tailored server.xml. This is it. It's not really that different from the regular server.xml file, so we may want to make the build system just apply a diff (?) instead of copying this whole file in as "server.xml" like I've set it up to do currently.. catalina/src/conf/tomcat-4.0.conf.xml This is one of the config files that tells Avalon about the Tomcat bar file. catalina/src/share/org/apache/catalina/logger/AvalonFileLogger.java Allows Catalina to log through Avalon. catalina/src/share/org/apache/catalina/startup/TomcatBlock.java The main Block class that makes it all happen. catalina/src/share/org/apache/catalina/startup/TomcatBlock.xinfo An Avalon Block descriptor file for TomcatBlock. catalina/src/share/org/apache/catalina/valves/AccessLogValveBase.java The superclass of both FileAccessLogValve and AvalonAccessLogValve. catalina/src/share/org/apache/catalina/valves/AvalonAccessLogValve.java This is an AccessLogValve that sends the web server access log through Avalon's logging system. catalina/src/share/org/apache/catalina/valves/FileAccessLogValve.java This is the stand-alone AccessLogValve that simply writes the output to a file on the filesystem. This class replaces the older, now obsolete AccessLogValve class. And that's it. Let me know what you think.. :) -- Jason Brittain Software Engineer, Olliance Inc. http://www.Olliance.com Current Maintainer, Locomotive Project http://www.Locomotive.org --------------050602020409080304080406 Content-Type: text/plain; name="avalon-MANIFEST.MF" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="avalon-MANIFEST.MF" Manifest-Version: 1.0 Created-By: Apache Avalon Project Name: org/apache/catalina/startup/TomcatBlock.class Avalon-Block: true --------------050602020409080304080406 Content-Type: text/xml; name="avalon-server.xml" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="avalon-server.xml" usersa password driverClassName org.hsql.jdbcDriver driverName jdbc:HypersonicSQL:database --------------050602020409080304080406 Content-Type: text/xml; name="tomcat-4.0.conf.xml" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="tomcat-4.0.conf.xml" /var/tomcat-4.0 --------------050602020409080304080406 Content-Type: text/plain; name="AvalonFileLogger.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="AvalonFileLogger.java" /* * $Header: /export/cvs/eas/projects/tomcat-4.0/src/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/logger/AvalonFileLogger.java,v 1.1.1.1 2001/02/08 21:43:05 jason Exp $ * $Revision: 1.1.1.1 $ * $Date: 2001/02/08 21:43:05 $ * * ==================================================================== * * 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 * modification, 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 acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 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 (INCLUDING, 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 * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.logger; import java.io.File; import java.io.IOException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.startup.TomcatBlock; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; import org.apache.log.Category; import org.apache.log.output.FileOutputLogTarget; import org.apache.log.Logger; import org.apache.log.LogKit; import org.apache.log.LogTarget; import org.apache.log.Priority; /** * Implementation of Logger that uses Avalon's logging facility, * and appends log messages to a file named {prefix}.{date}.{suffix} in a * configured directory, with an optional preceding timestamp. * * @author Jason Brittain * @version $Revision: 1.1.1.1 $ $Date: 2001/02/08 21:43:05 $ */ public final class AvalonFileLogger extends LoggerBase implements Lifecycle { // ----------------------------------------------------- Instance Variables /** * The Logger instance that will log our messages for us. */ protected Logger logger = null; /** * The name string of this version of the Tomcat 4 Block that * distinguishes it from other/different versions of the Tomcat 4 Block. * This name string is used for naming directories and paths, so the * characters used in the name are limited to those that can be used * in directory names. Example: "tomcat-4.0" */ private String tomcatVersion = "tomcat-unknown"; /** * The as-of date for the currently open log file, or a zero-length * string if there is no open log file. */ protected String dateStamp = ""; /** * A date formatter to format a Date into a date in the format * "yyyy-MM-dd". */ protected SimpleDateFormat dateFormatter = null; /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.logger.AvalonFileLogger/1.0"; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The prefix that is added to log file filenames. */ private String prefix = "catalina."; /** * The string manager for this package. */ private StringManager sm = StringManager.getManager(Constants.Package); /** * Has this component been started? */ private boolean started = false; /** * The suffix that is added to log file filenames. */ private String suffix = ".log"; /** * Should logged messages be date/time stamped? */ private boolean timestamp = false; // ------------------------------------------------------------- Properties /** * Return the log file prefix. */ public String getPrefix() { return (prefix); } /** * Set the log file prefix. * * @param prefix The new log file prefix */ public void setPrefix(String prefix) { String oldPrefix = this.prefix; this.prefix = prefix; support.firePropertyChange("prefix", oldPrefix, this.prefix); } /** * Return the log file suffix. */ public String getSuffix() { return (suffix); } /** * Set the log file suffix. * * @param suffix The new log file suffix */ public void setSuffix(String suffix) { String oldSuffix = this.suffix; this.suffix = suffix; support.firePropertyChange("suffix", oldSuffix, this.suffix); } /** * Return the timestamp flag. */ public boolean getTimestamp() { return (timestamp); } /** * Set the timestamp flag. * * @param timestamp The new timestamp flag */ public void setTimestamp(boolean timestamp) { boolean oldTimestamp = this.timestamp; this.timestamp = timestamp; support.firePropertyChange("timestamp", new Boolean(oldTimestamp), new Boolean(this.timestamp)); } // --------------------------------------------------------- Public Methods /** * Writes the specified message to a servlet log file, usually an event * log. The name and type of the servlet log is specific to the * servlet container. * * @param msg A String specifying the message to be written * to the log file */ public void log(String msg) { // Construct the timestamp we will use, if requested Timestamp ts = new Timestamp(System.currentTimeMillis()); String tsString = ts.toString().substring(0, 19); // Log this message, timestamped if necessary StringBuffer message = new StringBuffer(); if (timestamp) { message.append(tsString); message.append(" "); } message.append(msg); logger.info(message.toString()); } // -------------------------------------------------------- Private Methods /** * This method creates a Logger using the org.apache.log package. * Avalon uses this package for logging. */ public void createLogger() { // Set the tomcatVersion name, which we use as a directory name. tomcatVersion = TomcatBlock.getTomcatBlockVersion(); // Set the full pathname to the log file String logsBase = System.getProperty(tomcatVersion + ".logs.path"); String filename = prefix + dateStamp + suffix; String pathname = logsBase + File.separator + filename; // Register and create the Logger try { // Create a new log target that goes to a file LogTarget target = new FileOutputLogTarget(pathname); // Set the log format to only contain the log data we send in ((FileOutputLogTarget) target).setFormat("%{message}\\n"); // Add the log target to the logging system LogKit.addLogTarget(filename, target); // Create a log category with the same file name as our log target Category category = LogKit.createCategory(filename, Priority.INFO); // Create the logger for the category logger = LogKit.createLogger(category); // Hook up the logger with the target logger.addLogTarget(target); } catch (IOException e) { e.printStackTrace(); } } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Prepare for the beginning of active use of the public methods of this * component. This method should be called after configure(), * and before any of the public methods of the component are utilized. * * @exception IllegalStateException if this component has already been * started * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("fileLogger.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Initialize the timeZone and Date formatter TimeZone tz = TimeZone.getDefault(); dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); dateFormatter.setTimeZone(tz); dateStamp = dateFormatter.format(new Date()); createLogger(); } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @exception IllegalStateException if this component has not been started * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException { // Validate and update our current component state if (!started) throw new LifecycleException (sm.getString("fileLogger.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; } } --------------050602020409080304080406 Content-Type: text/plain; name="TomcatBlock.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="TomcatBlock.java" /* * $Header: /export/cvs/eas/projects/tomcat-4.0/src/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/TomcatBlock.java,v 1.1.1.1 2001/02/08 21:43:05 jason Exp $ * $Revision: 1.1.1.1 $ * $Date: 2001/02/08 21:43:05 $ * * ==================================================================== * * 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 * modification, 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 acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 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 (INCLUDING, 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 * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.startup; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.Iterator; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.phoenix.BlockContext; import org.apache.avalon.ConfigurationException; import org.apache.avalon.Configuration; import org.apache.avalon.Startable; import org.apache.avalon.Stoppable; import org.apache.avalon.blocks.AbstractBlock; import org.apache.avalon.util.io.IOUtil; import org.apache.catalina.Globals; /** * This class is part of the integration code that makes Tomcat 4 work * on top of Avalon. This version of the TomcatBlock requires Avalon * 3.1a1 or above. In order to compile TomcatBlock, you must first have * Avalon's avalonapi.jar or the compiled Avalon API classes on your * CLASSPATH before invoking the build target "dist-opt-avalon" in the * top level build file. * * @author Remy Maucherat * @author Jason Brittain * @version $Revision: 1.1.1.1 $ */ public final class TomcatBlock extends AbstractBlock implements Startable, Stoppable { // ----------------------------------------------------- Instance Variables /** * Catalina's catalina.home path (constructed from the root of the "sar" * and the version name of this Block. */ private String catalinaHome = null; /** * The name string of this version of the Tomcat 4 Block that * distinguishes it from other/different versions of the Tomcat 4 Block. * This name string is used for naming directories and paths, so the * characters used in the name are limited to those that can be used * in directory names. Example: "tomcat-4.0" */ private String tomcatVersion = "tomcat-unknown"; /** * Our specially-loaded Bootstrap class with its own URLClassLoader * that knows about the JDK's tools.jar (for JSP compiling of course). */ private Class bootstrap = null; /** * The base path to the directory where everything from the Avalon sar * file was deployed. This Block sits within this directory. */ private String sarPath = null; /** * The path to the deployed Tomcat 4 bin directory. */ private String binPath = null; /** * The path to the deployed Tomcat 4 conf directory. */ private String confPath = null; /** * The path to the deployed Tomcat 4 logs directory. */ private String logsPath = null; /** * The path to the deployed Tomcat 4 webapps directory. */ private String webappsPath = null; /** * The path to the deployed Tomcat 4 work directory. */ private String workPath = null; /** * The path to the deployed Tomcat 4 lib directory. */ private String libPath = null; /** * The path to the deployed Tomcat 4 server directory. */ private String serverPath = null; // ---------------------------------------------------------- Block Methods /** * This method is called just before init() each time the block is * run by Avalon. It is not called at Block deployment time, only * at each Block runtime. * * @param configuration the Block's Configuration object. */ public void configure(final Configuration configuration) throws ConfigurationException { // Set the tomcatVersion name, which we use as a directory name. tomcatVersion = TomcatBlock.getTomcatBlockVersion(); System.out.println(tomcatVersion + ": configure"); // Set up lots of filesystem paths that we need. setPaths(); // Build the full path to this Block's .bar file so we can deploy // directories to the filesystem.. // // FIXME: this probably isn't the way it should work! // String barPath = sarPath + File.separator + "blocks" + File.separator + tomcatVersion + ".bar"; // Deploy whole directories from the .bar file if we need to deployIfNecessaryFromFile(barPath); // Jasper won't work unless tools.jar is on the classpath.. // So, we make a new URLClassLoader that has tools.jar and all of // the other jars Catalina needs and then load Bootstrap from our // new ClassLoader. try { String jdkHome = System.getProperty("java.home"); if (jdkHome.endsWith("/jre")) { int index = jdkHome.lastIndexOf("/"); jdkHome = jdkHome.substring(0, index); jdkHome = jdkHome.replace('\\', '/'); } // Put all of the jars on the classpath that the catalina.sh // shell script would.. String slashedBinPath = binPath.replace('\\', '/'); URL[] loaderUrls = { new URL("file:" + jdkHome + "/lib/tools.jar"), new URL("file:" + slashedBinPath + "/bootstrap.jar"), new URL("file:" + slashedBinPath + "/naming.jar"), new URL("file:" + slashedBinPath + "/servlet.jar") }; URLClassLoader urlClassLoader = URLClassLoader.newInstance(loaderUrls, getClass().getClassLoader()); bootstrap = urlClassLoader.loadClass( "org.apache.catalina.startup.Bootstrap"); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * Starts up Tomcat/Catalina by calling the Bootstrap class's main method * with the correct argument ("start"). */ public void start() throws Exception { System.out.println(tomcatVersion + ": start"); try { String[] args = { "start" }; Class[] argTypes = new Class[1]; argTypes[0] = args.getClass(); Method mainMethod = bootstrap.getMethod("main", argTypes); Object[] reflectArgs = new Object[1]; reflectArgs[0] = args; mainMethod.invoke(null, reflectArgs); } catch (Throwable t) { t.printStackTrace(); } } /** * Stops Tomcat/Catalina by calling the Bootstrap class's main method * with the correct argument ("stop"). */ public void stop() throws Exception { System.out.println(tomcatVersion + ": stop"); try { String[] args = { "stop" }; Class[] argTypes = new Class[1]; argTypes[0] = args.getClass(); Method mainMethod = bootstrap.getMethod("main", argTypes); Object[] reflectArgs = new Object[1]; reflectArgs[0] = args; mainMethod.invoke(null, reflectArgs); } catch (Throwable t) { t.printStackTrace(); } } /** * Sets lots of paths so that we can deploy several directories from * the .bar file to the filesystem. This method also sets these paths * as System properties with the names: *
*
* tomcat-4.0.sar.path
* tomcat-4.0.catalina.home
* tomcat-4.0.bin.path
* tomcat-4.0.conf.path
* tomcat-4.0.logs.path
* tomcat-4.0.webapps.path
* tomcat-4.0.work.path
* tomcat-4.0.lib.path
* tomcat-4.0.server.path
*
* Substitute the tomcat version string from getTomcatBlockVersion() * in the above names. */ protected void setPaths() { // Set the catalinaHome path BlockContext blockContext = getBlockContext(); sarPath = blockContext.getBaseDirectory().getAbsolutePath(); catalinaHome = sarPath + File.separator + "var" + File.separator + tomcatVersion; // Set some paths: binPath, confPath, logsPath, webappsPath, workPath, // libPath, and serverPath binPath = catalinaHome + File.separator + "bin"; confPath = catalinaHome + File.separator + "conf"; logsPath = sarPath + File.separator + "logs" + File.separator + tomcatVersion; webappsPath = catalinaHome + File.separator + "webapps"; workPath = catalinaHome + File.separator + "work"; libPath = catalinaHome + File.separator + "lib"; serverPath = catalinaHome + File.separator + "server"; // Set system properties for all of our paths so we can get // and use these paths later.. System.setProperty(tomcatVersion + ".sar.path", sarPath); System.setProperty(tomcatVersion + ".catalina.home", catalinaHome); System.setProperty(tomcatVersion + ".bin.path", binPath); System.setProperty(tomcatVersion + ".conf.path", confPath); System.setProperty(tomcatVersion + ".logs.path", logsPath); System.setProperty(tomcatVersion + ".webapps.path", webappsPath); System.setProperty(tomcatVersion + ".work.path", workPath); System.setProperty(tomcatVersion + ".lib.path", libPath); System.setProperty(tomcatVersion + ".server.path", serverPath); // Set the catalina.home path as a System property System.setProperty("catalina.home", catalinaHome); /* System.out.println(" sarPath=" + sarPath); System.out.println(" catalinaHome=" + catalinaHome); System.out.println(" binPath=" + binPath); System.out.println(" confPath=" + confPath); System.out.println(" logsPath=" + logsPath); System.out.println(" webappsPath=" + webappsPath); System.out.println(" workPath=" + workPath); System.out.println(" libPath=" + libPath); System.out.println(" serverPath=" + serverPath); */ } /** * This method checks to see which directories have been deployed from * the .bar file (if any) and if something's missing it will deploy it * out of the .bar file onto the filesystem where it should go. Since * deployment only happens when the directories to be deployed are * absent on the filesystem, deployment usually only happens on the * first run of the Block after its .bar file deployed into Avalon. * * @param barPath the full pathname to the .bar file that this TomcatBlock * is packaged in. */ protected void deployIfNecessaryFromFile(String barPath) { // Install the Block's files that need to be outside the .bar file, // if they haven't already been installed. if (!new File(binPath).isDirectory()) { deployDir("bin", binPath, barPath); } if (!new File(confPath).isDirectory()) { deployDir("tomcat-conf", confPath, barPath); } if (!new File(logsPath).isDirectory()) { new File(logsPath).mkdir(); } if (!new File(webappsPath).isDirectory()) { deployDir("webapps", webappsPath, barPath); } if (!new File(workPath).isDirectory()) { deployDir("work", workPath, barPath); } if (!new File(libPath).isDirectory()) { deployDir("tomcat-lib", libPath, barPath); } if (!new File(serverPath).isDirectory()) { deployDir("server", serverPath, barPath); } } /** * Formulate and return a Tomcat Block version string that can be used * in directory paths for the Block. This name is created from the * Globals SERVER_INFO string, but is tailored to exclude the minor * release number (like "-b2" or "-dev"). */ public static String getTomcatBlockVersion() { String version = "tomcat-"; int beginIndex = Globals.SERVER_INFO.lastIndexOf("/"); if (beginIndex != -1) { int endIndex = Globals.SERVER_INFO.substring(beginIndex + 1).indexOf("-"); if (endIndex == -1) version = version + Globals.SERVER_INFO.substring(beginIndex + 1); else version = version + Globals.SERVER_INFO.substring(beginIndex + 1, endIndex + beginIndex + 1); } else version = version + "unknown"; return version; } /** * This method deploys a directory's contents (just the contents, not * the directory itself) from the bar file to the filesystem. * * @param directory the name of the directory to copy from the bar file. * @param destination the base filesystem directory to copy it into. * @param barPath the absolute filesystem path to the bar file. */ protected void deployDir(String directory, String destination, String barPath) { ZipFile zipFile; try { zipFile = new ZipFile(barPath); } catch(IOException e) { e.printStackTrace(); return; } Enumeration entries = zipFile.entries(); while(entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); if (!entry.getName().startsWith(directory)) continue; String name = entry.getName().replace( '/', File.separatorChar); // Clip off the directory's name int index = name.indexOf(File.separator); if (index != -1) name = name.substring(index + 1); //System.out.println("deploying " + name + " --> " + destination); if (entry.isDirectory()) { if (name.equals(directory)) continue; // Create the directory on the filesystem File newdir = new File(destination + File.separator + name); if (!newdir.mkdirs()) System.out.println("Could not create directory " + newdir.getAbsolutePath()); } else { // Copy the file to the filesystem File copyto = new File(destination, name); InputStream input = null; OutputStream output = null; try { copyto.getParentFile().mkdirs(); output = new FileOutputStream(copyto); input = zipFile.getInputStream(entry); IOUtil.copy(input, output); } catch(IOException ioe) { ioe.printStackTrace(); } finally { IOUtil.shutdownStream(input); IOUtil.shutdownStream(output); } } } } } --------------050602020409080304080406 Content-Type: text/plain; name="TomcatBlock.xinfo" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="TomcatBlock.xinfo" --------------050602020409080304080406 Content-Type: text/plain; name="AccessLogValveBase.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="AccessLogValveBase.java" /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 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 (INCLUDING, 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 * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.valves; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.HttpResponse; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.ValveContext; /** *

Abstract implementation of the Valve interface that generates a * web server access log with the detailed line contents matching a * configurable pattern. The syntax of the available patterns is similar to * that supported by the Apache mod_log_config module. As an * additional feature, automatic rollover of log files when the date changes * is also supported.

* *

Patterns for the logged message may include constant text or any of the * following replacement strings, for which the corresponding information * from the specified Response is substituted:

*
    *
  • %a - Remote IP address *
  • %A - Local IP address *
  • %b - Bytes sent, excluding HTTP headers, or '-' if no bytes * were sent *
  • %B - Bytes sent, excluding HTTP headers *
  • %h - Remote host name *
  • %H - Request protocol *
  • %l - Remote logical username from identd (always returns '-') *
  • %m - Request method *
  • %p - Local port *
  • %q - Query string (prepended with a '?' if it exists, otherwise * an empty string *
  • %r - First line of the request *
  • %s - HTTP status code of the response *
  • %t - Date and time, in Common Log Format format *
  • %u - Remote user that was authenticated *
  • %U - Requested URL path *
  • %v - Local server name *
*

In addition, the caller can specify one of the following aliases for * commonly utilized patterns:

*
    *
  • common - %h %l %u %t "%r" %s %b *
* *

FIXME - Improve the parsing so that things like * %{xxx}i can be implemented.

* *

When subclassing this class, you must implement log(), * and also call the timeInit() method before the first use * of your valve (usually from the lifecycle start method). * * @author Craig R. McClanahan * @author Jason Brittain * @version $Revision: 1.1.1.1 $ $Date: 2001/02/08 21:43:05 $ */ public abstract class AccessLogValveBase extends ValveBase { // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class with default property values. */ public AccessLogValveBase() { super(); setPattern("common"); } // ----------------------------------------------------- Instance Variables /** * The as-of date for the currently open log file, or a zero-length * string if there is no open log file. */ protected String dateStamp = ""; /** * The default directory in which the log files are created. */ protected String directory = "logs"; /** * The prefix that is added to log file filenames. */ protected String prefix = "access_log."; /** * The suffix that is added to log file filenames. */ protected String suffix = ".txt"; /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.valves.AccessLogValveBase/1.0"; /** * The set of month abbreviations for log messages. */ protected static final String months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /** * If the current log pattern is the same as the common access log * format pattern, then we'll set this variable to true and log in * a more optimal and hard-coded way. */ private boolean common = false; /** * The pattern used to format our access log lines. */ private String pattern = null; /** * Has this component been started yet? */ private boolean started = false; /** * A date formatter to format a Date into a date in the format * "yyyy-MM-dd". */ protected SimpleDateFormat dateFormatter = null; /** * A date formatter to format Dates into a day string in the format * "dd". */ private SimpleDateFormat dayFormatter = null; /** * A date formatter to format a Date into a month string in the format * "MM". */ private SimpleDateFormat monthFormatter = null; /** * A date formatter to format a Date into a year string in the format * "yyyy". */ private SimpleDateFormat yearFormatter = null; /** * A date formatter to format a Date into a time in the format * "kk:mm:ss" (kk is a 24-hour representation of the hour). */ private SimpleDateFormat timeFormatter = null; /** * The time zone relative to GMT. */ private String timeZone = null; /** * The system time when we last updated the Date that this valve * uses for log lines. */ protected Date currentDate = null; /** * When formatting log lines, we often use strings like this one (" "). */ private String space = " "; // ------------------------------------------------------------- Properties /** * Return the directory in which we create log files. */ public String getDirectory() { return (directory); } /** * Set the directory in which we create log files. * * @param directory The new log file directory */ public void setDirectory(String directory) { this.directory = directory; } /** * Return the log file prefix. */ public String getPrefix() { return (prefix); } /** * Set the log file prefix. * * @param prefix The new log file prefix */ public void setPrefix(String prefix) { this.prefix = prefix; } /** * Return the log file suffix. */ public String getSuffix() { return (suffix); } /** * Set the log file suffix. * * @param suffix The new log file suffix */ public void setSuffix(String suffix) { this.suffix = suffix; } /** * Return descriptive information about this implementation. */ public String getInfo() { return (this.info); } /** * Return the format pattern. */ public String getPattern() { return (this.pattern); } /** * Set the format pattern, first translating any recognized alias. * * @param pattern The new pattern */ public void setPattern(String pattern) { if (pattern == null) pattern = ""; if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) pattern = Constants.AccessLog.COMMON_PATTERN; this.pattern = pattern; if (this.pattern.equals(Constants.AccessLog.COMMON_PATTERN)) common = true; else common = false; } // --------------------------------------------------------- Public Methods /** * Log a message summarizing the specified request and response, according * to the format specified by the pattern property. * * @param request Request being processed * @param response Response being processed * @param context The valve context used to invoke the next valve * in the current processing pipeline * * @exception IOException if an input/output error has occurred * @exception ServletException if a servlet error has occurred */ public void invoke(Request request, Response response, ValveContext context) throws IOException, ServletException { // Pass this request on to the next valve in our pipeline context.invokeNext(request, response); Date date = getDate(); StringBuffer result = new StringBuffer(); // Check to see if we should log using the "common" access log pattern if (common) { String value = null; ServletRequest req = request.getRequest(); HttpServletRequest hreq = null; if (req instanceof HttpServletRequest) hreq = (HttpServletRequest) req; result.append(req.getRemoteHost()); result.append(" - "); if (hreq != null) value = hreq.getRemoteUser(); if (value == null) result.append("- "); else { result.append(value); result.append(space); } result.append("["); result.append(dayFormatter.format(date)); // Day result.append('/'); result.append(lookup(monthFormatter.format(date))); // Month result.append('/'); result.append(yearFormatter.format(date)); // Year result.append(':'); result.append(timeFormatter.format(date)); // Time result.append(space); result.append(timeZone); // Time Zone result.append("] \""); result.append(hreq.getMethod()); result.append(space); result.append(hreq.getRequestURI()); result.append(space); result.append(hreq.getProtocol()); result.append("\" "); result.append(((HttpResponse) response).getStatus()); result.append(space); int length = response.getContentCount(); if (length <= 0) value = "-"; else value = "" + length; result.append(value); } else { // Generate a message based on the defined pattern boolean replace = false; for (int i = 0; i < pattern.length(); i++) { char ch = pattern.charAt(i); if (replace) { result.append(replace(ch, date, request, response)); replace = false; } else if (ch == '%') { replace = true; } else { result.append(ch); } } } log(result.toString(), date); } /** * Log the specified message. * * @param message Message to be logged * @param date the current Date object (so this method doesn't need to * create a new one) */ public abstract void log(String message, Date date); // ---------------------------------------------------- Protected Methods /** * This method only needs to be called once before this valve * is invoked. It initializes many time-related instance variables * like the timezone, date formatters, and the current datestamp. */ protected void timeInit() { // Initialize the timeZone, Date formatters, and currentDate TimeZone tz = TimeZone.getDefault(); timeZone = "" + (tz.getRawOffset() / (60 * 60 * 10)); if (timeZone.length() < 5) timeZone = timeZone.substring(0, 1) + "0" + timeZone.substring(1, timeZone.length()); dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); dateFormatter.setTimeZone(tz); dayFormatter = new SimpleDateFormat("dd"); dayFormatter.setTimeZone(tz); monthFormatter = new SimpleDateFormat("MM"); monthFormatter.setTimeZone(tz); yearFormatter = new SimpleDateFormat("yyyy"); yearFormatter.setTimeZone(tz); timeFormatter = new SimpleDateFormat("kk:mm:ss"); timeFormatter.setTimeZone(tz); currentDate = new Date(); dateStamp = dateFormatter.format(currentDate); } /** * Return the month abbreviation for the specified month, which must * be a two-digit String. * * @param month Month number ("01" .. "12"). */ protected String lookup(String month) { int index; try { index = Integer.parseInt(month) - 1; } catch (Throwable t) { index = 0; // Can not happen, in theory } return (months[index]); } /** * This method returns a Date object that is accurate to within one * second. If a thread calls this method to get a Date and it's been * less than 1 second since a new Date was created, this method * simply gives out the same Date again so that the system doesn't * spend time creating Date objects unnecessarily. */ protected Date getDate() { // Only create a new Date once per second, max. long systime = System.currentTimeMillis(); if ((systime - currentDate.getTime()) > 1000) { currentDate = new Date(systime); } return currentDate; } /** * Return the replacement text for the specified pattern character. * * @param pattern Pattern character identifying the desired text * @param date the current Date so that this method doesn't need to * create one * @param request Request being processed * @param response Response being processed */ protected String replace(char pattern, Date date, Request request, Response response) { String value = null; ServletRequest req = request.getRequest(); HttpServletRequest hreq = null; if (req instanceof HttpServletRequest) hreq = (HttpServletRequest) req; ServletResponse res = response.getResponse(); HttpServletResponse hres = null; if (res instanceof HttpServletResponse) hres = (HttpServletResponse) res; if (pattern == 'a') { value = req.getRemoteAddr(); } else if (pattern == 'A') { value = "127.0.0.1"; // FIXME } else if (pattern == 'b') { int length = response.getContentCount(); if (length <= 0) value = "-"; else value = "" + length; } else if (pattern == 'B') { value = "" + response.getContentLength(); } else if (pattern == 'h') { value = req.getRemoteHost(); } else if (pattern == 'H') { value = req.getProtocol(); } else if (pattern == 'l') { value = "-"; } else if (pattern == 'm') { if (hreq != null) value = hreq.getMethod(); else value = ""; } else if (pattern == 'p') { value = "" + req.getServerPort(); } else if (pattern == 'q') { String query = null; if (hreq != null) query = hreq.getQueryString(); if (query != null) value = "?" + query; else value = ""; } else if (pattern == 'r') { if (hreq != null) value = hreq.getMethod() + space + hreq.getRequestURI() + space + hreq.getProtocol(); else value = "- - " + req.getProtocol(); } else if (pattern == 's') { if (hres != null) value = "" + ((HttpResponse) response).getStatus(); else value = "-"; } else if (pattern == 't') { StringBuffer temp = new StringBuffer("["); temp.append(dayFormatter.format(date)); // Day temp.append('/'); temp.append(lookup(monthFormatter.format(date))); // Month temp.append('/'); temp.append(yearFormatter.format(date)); // Year temp.append(':'); temp.append(timeFormatter.format(date)); // Time temp.append(' '); temp.append(timeZone); // Timezone temp.append(']'); value = temp.toString(); } else if (pattern == 'u') { if (hreq != null) value = hreq.getRemoteUser(); if (value == null) value = "-"; } else if (pattern == 'U') { if (hreq != null) value = hreq.getRequestURI(); else value = "-"; } else if (pattern == 'v') { value = req.getServerName(); } else { value = "???" + pattern + "???"; } if (value == null) return (""); else return (value); } } --------------050602020409080304080406 Content-Type: text/plain; name="AvalonAccessLogValve.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="AvalonAccessLogValve.java" /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 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 (INCLUDING, 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 * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.valves; import java.io.File; import java.io.IOException; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.Globals; import org.apache.catalina.HttpResponse; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.ValveContext; import org.apache.catalina.startup.TomcatBlock; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; import org.apache.log.Category; import org.apache.log.output.FileOutputLogTarget; import org.apache.log.Logger; import org.apache.log.LogKit; import org.apache.log.LogTarget; import org.apache.log.Priority; /** * This implementation sends all logging output to the Avalon framework's * logging package. It allows Catalina to log through Avalon which should * eventually allow the administrator to send the log data to various * destinations such as a filesystem, database, or to another log machine * across the network -- without modifying Catalina any further. * * @author Jason Brittain * @version $Revision: 1.1.1.1 $ $Date: 2001/02/08 21:43:05 $ */ public final class AvalonAccessLogValve extends AccessLogValveBase implements Lifecycle { // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class with default property values. */ public AvalonAccessLogValve() { super(); setPattern("common"); } // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.valves.AvalonAccessLogValve/1.0"; /** * The Logger instance that will log our messages for us. */ protected Logger logger = null; /** * The name string of this version of the Tomcat 4 Block that * distinguishes it from other/different versions of the Tomcat 4 Block. * This name string is used for naming directories and paths, so the * characters used in the name are limited to those that can be used * in directory names. Example: "tomcat-4.0" */ private String tomcatVersion = null; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The string manager for this package. */ private StringManager sm = StringManager.getManager(Constants.Package); /** * Has this component been started yet? */ private boolean started = false; // ------------------------------------------------------------- Properties /** * Return descriptive information about this implementation. */ public String getInfo() { return (this.info); } // --------------------------------------------------------- Public Methods /** * Log the specified message to the log file, switching files if the date * has changed since the previous log call. * * @param message Message to be logged * @param date the current Date object (so this method doesn't need to * create a new one) */ public void log(String message, Date date) { logger.info(message); } // -------------------------------------------------------- Private Methods /** * This method creates a Logger using the org.apache.log package. * Avalon uses this package for logging. */ public void createLogger() { // Set the tomcatVersion name, which we use as a directory name. tomcatVersion = TomcatBlock.getTomcatBlockVersion(); // Set the full pathname to the log file String logsBase = System.getProperty(tomcatVersion + ".logs.path"); String filename = prefix + dateStamp + suffix; String pathname = logsBase + File.separator + filename; // Register and create the Logger try { // Create a new log target that goes to a file LogTarget target = new FileOutputLogTarget(pathname); // Set the log format to only contain the log data we send in ((FileOutputLogTarget) target).setFormat("%{message}\\n"); // Add the log target to the logging system LogKit.addLogTarget(filename, target); // Create a log category with the same file name as our log target Category category = LogKit.createCategory(filename, Priority.INFO); // Create the logger for the category logger = LogKit.createLogger(category); // Hook up the logger with the target logger.addLogTarget(target); } catch (IOException e) { e.printStackTrace(); } } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Prepare for the beginning of active use of the public methods of this * component. This method should be called after configure(), * and before any of the public methods of the component are utilized. * * @exception IllegalStateException if this component has already been * started * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("accessLogValve.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; timeInit(); createLogger(); } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @exception IllegalStateException if this component has not been started * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException { // Validate and update our current component state if (!started) throw new LifecycleException (sm.getString("accessLogValve.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; } } --------------050602020409080304080406 Content-Type: text/plain; name="FileAccessLogValve.java" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="FileAccessLogValve.java" /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, 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 acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 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 (INCLUDING, 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 * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.catalina.valves; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.HttpResponse; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Request; import org.apache.catalina.Response; import org.apache.catalina.ValveContext; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.util.StringManager; /** * This Valve implementation writes access logs to files on the filesystem. * See the class comments of AccessLogValveBase for information about how * the log lines are generated. This Valve breaks up log output into daily * log files by opening a new log file each day, and the filename of the log * file contains the date. This process is commonly known as "log file * rolling". * * @author Craig R. McClanahan * @author Jason Brittain * @version $Revision: 1.1.1.1 $ $Date: 2001/02/08 21:43:05 $ */ public final class FileAccessLogValve extends AccessLogValveBase implements Lifecycle { // ----------------------------------------------------------- Constructors /** * Construct a new instance of this class with default property values. */ public FileAccessLogValve() { super(); setPattern("common"); } // ----------------------------------------------------- Instance Variables /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.valves.FileAccessLogValve/1.0"; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The string manager for this package. */ private StringManager sm = StringManager.getManager(Constants.Package); /** * Has this component been started yet? */ private boolean started = false; /** * The PrintWriter to which we are currently logging, if any. */ private PrintWriter writer = null; // ------------------------------------------------------------- Properties /** * Return descriptive information about this implementation. */ public String getInfo() { return (this.info); } // -------------------------------------------------------- Public Methods /** * Log the specified message to the log file, switching files if the date * has changed since the previous log call. * * @param message Message to be logged * @param date the current Date object (so this method doesn't need to * create a new one) */ public void log(String message, Date date) { // Only do a logfile switch check once a second, max. long systime = System.currentTimeMillis(); if ((systime - currentDate.getTime()) > 1000) { // We need a new currentDate currentDate = new Date(systime); // Check for a change of date String tsDate = dateFormatter.format(currentDate); // If the date has changed, switch log files if (!dateStamp.equals(tsDate)) { synchronized (this) { close(); dateStamp = tsDate; open(); } } } // Log this message if (writer != null) { writer.println(message); } } // -------------------------------------------------------- Private Methods /** * Close the currently open log file (if any) */ private synchronized void close() { if (writer == null) return; writer.flush(); writer.close(); writer = null; dateStamp = ""; } /** * Open the new log file for the date specified by dateStamp. */ private synchronized void open() { // Create the directory if necessary File dir = new File(directory); if (!dir.isAbsolute()) dir = new File(System.getProperty("catalina.home") + File.separator + directory); dir.mkdirs(); // Open the current log file try { String pathname = dir.getAbsolutePath() + File.separator + prefix + dateStamp + suffix; writer = new PrintWriter(new FileWriter(pathname, true), true); } catch (IOException e) { writer = null; } } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Remove a lifecycle event listener from this component. * * @param listener The listener to add */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Prepare for the beginning of active use of the public methods of this * component. This method should be called after configure(), * and before any of the public methods of the component are utilized. * * @exception IllegalStateException if this component has already been * started * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException { // Validate and update our current component state if (started) throw new LifecycleException (sm.getString("accessLogValve.alreadyStarted")); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; timeInit(); open(); } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @exception IllegalStateException if this component has not been started * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException { // Validate and update our current component state if (!started) throw new LifecycleException (sm.getString("accessLogValve.notStarted")); lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; close(); } } --------------050602020409080304080406--