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
Manifest-Version: 1.0 Created-By: Apache Avalon Project Name: org/apache/catalina/startup/TomcatBlock.class Avalon-Block: true
<!-- This is an example server configuration file for Tomcat running on --> <!-- top of the Avalon server framework. Note: these settings won't --> <!-- work when you run Tomcat without Avalon! --> <!-- Note that component elements are nested corresponding to their parent-child relationships with each other --> <!-- A "Server" is a singleton element that represents the entire JVM, which may contain one or more "Service" instances. The Server listens for a shutdown command on the indicated port. Note: A "Server" is not itself a "Container", so you may not define subcomponents such as "Valves" or "Loggers" at this level. --> <Server port="8005" shutdown="SHUTDOWN" debug="0"> <!-- A "Service" is a collection of one or more "Connectors" that share a single "Container" (and therefore the web applications visible within that Container). Normally, that Container is an "Engine", but this is not required. Note: A "Service" is not itself a "Container", so you may not define subcomponents such as "Valves" or "Loggers" at this level. --> <!-- Define the Tomcat Stand-Alone Service --> <Service name="Tomcat-Standalone"> <!-- A "Connector" represents an endpoint by which requests are received and responses are returned. Each Connector passes requests on to the associated "Container" (normally an Engine) for processing. By default, a non-SSL HTTP/1.1 Connector is established on port 8080. You can also enable an SSL HTTP/1.1 Connector on port 8443 by following the instructions below and uncommenting the second Connector entry. SSL support requires the following steps: * Download and install JSSE 1.0.2 or later, and put the JAR files into "$JAVA_HOME/jre/lib/ext". * Edit "$JAVA_HOME/jre/lib/security/java.security" and add security.provider.2=com.sun.net.ssl.internal.ssl.Provider * Execute: keytool -genkey -alias tomcat -keyalg RSA with a password value of "changeit". --> <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8080" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0" connectionTimeout="60000"/> <!-- Note : To disable connection timeouts, set connectionTimeout value to -1 --> <!-- Define an SSL HTTP/1.1 Connector on port 8443 --> <!-- <Connector className="org.apache.catalina.connector.http.HttpConnector" port="8443" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0" scheme="https" secure="true"> <Factory className="org.apache.catalina.net.SSLServerSocketFactory" clientAuth="false" protocol="TLS"/> </Connector> --> <!-- Define a non-SSL HTTP/1.0 Test Connector on port 8081 --> <!-- <Connector className="org.apache.catalina.connector.http10.HttpConnector" port="8081" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0"/> --> <!-- An Engine represents the entry point (within Catalina) that processes every request. The Engine implementation for Tomcat stand alone analyzes the HTTP headers included with the request, and passes them on to the appropriate Host (virtual host). --> <!-- Define the top level container in our container hierarchy --> <Engine name="Standalone" defaultHost="localhost" debug="0"> <!-- The request dumper valve dumps useful debugging information about the request headers and cookies that were received, and the response headers and cookies that were sent, for all requests received by this instance of Tomcat. If you care only about requests to a particular virtual host, or a particular application, nest this element inside the corresponding <Host> or <Context> entry instead. For a similar mechanism that is portable to all Servlet 2.3 containers, check out the "RequestDumperFilter" Filter in the example application (the source for this filter may be found in "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters"). Request dumping is disabled by default. Uncomment the following element to enable it. --> <!-- <Valve className="org.apache.catalina.valves.RequestDumperValve"/> --> <!-- Global logger unless overridden at lower levels --> <Logger className="org.apache.catalina.logger.AvalonFileLogger" prefix="catalina_log." suffix=".txt" timestamp="true"/> <!-- Because this Realm is here, an instance will be shared globally --> <Realm className="org.apache.catalina.realm.MemoryRealm" /> <!-- Replace the above Realm with one of the following to get a Realm stored in a database and accessed via JDBC --> <!-- <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" driverName="org.gjt.mm.mysql.Driver" connectionURL="jdbc:mysql://localhost/authority?user=test;password=test" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name" /> --> <!-- <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" driverName="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL?user=scott;password=tiger" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name" /> --> <!-- <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99" driverName="sun.jdbc.odbc.JdbcOdbcDriver" connectionURL="jdbc:odbc:CATALINA" userTable="users" userNameCol="user_name" userCredCol="user_pass" userRoleTable="user_roles" roleNameCol="role_name" /> --> <!-- Define the default virtual host --> <Host name="localhost" debug="0" appBase="webapps" unpackWARs="true"> <!-- Normally, users must authenticate themselves to each web app individually. Uncomment the following entry if you would like a user to be authenticated the first time they encounter a resource protected by a security constraint, and then have that user identity maintained across *all* web applications contained in this virtual host. --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" debug="0"/> --> <!-- Access log processes all requests for this virtual host. By default, log files are created in the "logs" directory relative to $CATALINA_HOME. If you wish, you can specify a different directory with the "directory" attribute. Specify either a relative (to $CATALINA_HOME) or absolute path to the desired directory. --> <Valve className="org.apache.catalina.valves.AvalonAccessLogValve" prefix="localhost_access_log." suffix=".txt" pattern="common"/> <!-- Logger shared by all Contexts related to this virtual host. By default (when using FileLogger), log files are created in the "logs" directory relative to $CATALINA_HOME. If you wish, you can specify a different directory with the "directory" attribute. Specify either a relative (to $CATALINA_HOME) or absolute path to the desired directory.--> <Logger className="org.apache.catalina.logger.AvalonFileLogger" prefix="localhost_log." suffix=".txt" timestamp="true"/> <!-- Define properties for each web application. This is only needed if you want to set non-default properties, or have web application document roots in places other than the virtual host's appBase directory. --> <!-- Tomcat Root Context --> <!-- <Context path="" docBase="ROOT" debug="0"/> --> <!-- Tomcat Examples Context --> <Context path="/examples" docBase="examples" debug="0" reloadable="true"> <Logger className="org.apache.catalina.logger.AvalonFileLogger" prefix="localhost_examples_log." suffix=".txt" timestamp="true"/> <Ejb name="ejb/EmplRecord" type="Entity" home="com.wombat.empl.EmployeeRecordHome" remote="com.wombat.empl.EmployeeRecord"/> <Environment name="maxExemptions" type="java.lang.Integer" value="15"/> <Parameter name="context.param.name" value="context.param.value" override="false"/> <Resource name="jdbc/EmployeeAppDb" auth="SERVLET" type="javax.sql.DataSource"/> <ResourceParams name="jdbc/TestDB"> <parameter><name>user</name><value>sa</value></parameter> <parameter><name>password</name><value></value></parameter> <parameter><name>driverClassName</name> <value>org.hsql.jdbcDriver</value></parameter> <parameter><name>driverName</name> <value>jdbc:HypersonicSQL:database</value></parameter> </ResourceParams> </Context> </Host> </Engine> </Service> <!-- The MOD_WEBAPP connector is used to connect Apache 1.3 with Tomcat 4.0 as its servlet container. This is built by following these steps: - cd {TOMCAT-SRC-HOME}/connectors - make - (Edit "Makedefs" as needed for your installation) - make - su root - cp connectors/apache-1.3/mod_webapp.so {APACHE_HOME}/libexec - exit To configure the Apache side, you must ensure that you have a "ServerName" directive defined in "httpd.conf". Then, lines like these to the bottom of your "httpd.conf" file: LoadModule webapp_module libexec/mod_webapp.so WebAppConnection warpConnection warp localhost:8008 WebAppMount examples warpConnection /examples/ Finally, modify the "defaultHost" attribute in the "Engine" directive below to match the "ServerName" setting defined in "https.conf". The next time you restart Apache (after restarting Tomcat, if needed) the connection will be established, and all applications you make visible via "WebAppMount" directives can be accessed through Apache. --> <!-- Define an Apache-Connector Service --> <Service name="Tomcat-Apache"> <Connector className="org.apache.catalina.connector.warp.WarpConnector" port="8008" minProcessors="5" maxProcessors="75" acceptCount="10" debug="0"/> <!-- Replace "localhost" with what your Apache "ServerName" is set to --> <Engine className="org.apache.catalina.connector.warp.WarpEngine" name="Apache" defaultHost="localhost" debug="0" appBase="webapps"> <!-- Global logger unless overridden at lower levels --> <Logger className="org.apache.catalina.logger.AvalonFileLogger" prefix="apache_log." suffix=".txt" timestamp="true"/> <!-- Because this Realm is here, an instance will be shared globally --> <Realm className="org.apache.catalina.realm.MemoryRealm" /> </Engine> </Service> </Server>
<?xml version="1.0"?> <avalon> <block class="org.apache.catalina.startup.TomcatBlock" name="tomcat-4.0" > <logger name="Servlet container" destinationURL="/logs/catalina.log" priority="DEBUG"/> <configuration> <path>/var/tomcat-4.0</path> </configuration> </block> </avalon>
/* * $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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. * * [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 <b>Logger</b> 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 <a href="mailto:[EMAIL PROTECTED]">Jason Brittain</a> * @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 <code>String</code> 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 <code>configure()</code>, * 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; } }
/* * $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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. * * [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 <a href="mailto:[EMAIL PROTECTED]">Remy Maucherat</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jason Brittain</a> * @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: * <br> * <blockquote> * tomcat-4.0.sar.path<br> * tomcat-4.0.catalina.home<br> * tomcat-4.0.bin.path<br> * tomcat-4.0.conf.path<br> * tomcat-4.0.logs.path<br> * tomcat-4.0.webapps.path<br> * tomcat-4.0.work.path<br> * tomcat-4.0.lib.path<br> * tomcat-4.0.server.path<br> * </blockquote> * 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); } } } } }
<?xml version="1.0"?> <blockinfo> <meta> <contributors> <author name="Remy Maucherat" email="[EMAIL PROTECTED]"/> <author name="Jason Brittain" email="[EMAIL PROTECTED]"/> </contributors> </meta> <!-- services that are offered by this block --> <services> <service name="org.apache.phoenix.Block" version="1.0.0" /> </services> </blockinfo>
/* * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. * * [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; /** * <p>Abstract implementation of the <b>Valve</b> 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 <code>mod_log_config</code> module. As an * additional feature, automatic rollover of log files when the date changes * is also supported.</p> * * <p>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:</p> * <ul> * <li><b>%a</b> - Remote IP address * <li><b>%A</b> - Local IP address * <li><b>%b</b> - Bytes sent, excluding HTTP headers, or '-' if no bytes * were sent * <li><b>%B</b> - Bytes sent, excluding HTTP headers * <li><b>%h</b> - Remote host name * <li><b>%H</b> - Request protocol * <li><b>%l</b> - Remote logical username from identd (always returns '-') * <li><b>%m</b> - Request method * <li><b>%p</b> - Local port * <li><b>%q</b> - Query string (prepended with a '?' if it exists, otherwise * an empty string * <li><b>%r</b> - First line of the request * <li><b>%s</b> - HTTP status code of the response * <li><b>%t</b> - Date and time, in Common Log Format format * <li><b>%u</b> - Remote user that was authenticated * <li><b>%U</b> - Requested URL path * <li><b>%v</b> - Local server name * </ul> * <p>In addition, the caller can specify one of the following aliases for * commonly utilized patterns:</p> * <ul> * <li><b>common</b> - <code>%h %l %u %t "%r" %s %b</code> * </ul> * * <p><b>FIXME</b> - Improve the parsing so that things like * <code>%{xxx}i</code> can be implemented.</p> * * <p>When subclassing this class, you must implement <code>log()</code>, * and also call the <code>timeInit()</code> 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 <code>pattern</code> 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); } }
/* * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. * * [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 <a href="mailto:[EMAIL PROTECTED]">Jason Brittain</a> * @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 <code>configure()</code>, * 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; } }
/* * ==================================================================== * * 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 [EMAIL PROTECTED] * * 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 * <http://www.apache.org/>. * * [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 <a href="mailto:[EMAIL PROTECTED]">Jason Brittain</a> * @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 <code>dateStamp</code>. */ 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 <code>configure()</code>, * 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(); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]