You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@excalibur.apache.org by le...@apache.org on 2004/08/05 17:09:39 UTC

svn commit: rev 35739 - in excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http: . server

Author: leif
Date: Thu Aug  5 08:09:39 2004
New Revision: 35739

Added:
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/FavIconHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLCreateSamplesHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSampleLeasesHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/favicon.ico   (contents, props changed)
Modified:
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/AbstractXMLHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/InstrumentManagerHTTPConnector.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/SampleChartHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSnapshotsHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/AbstractHTTPURLHandler.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPServer.java
   excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPURLHandler.java
Log:
Add support for batch updates.
Handle requests for the favicon.ico image.
Add an optional access log.

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/AbstractXMLHandler.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/AbstractXMLHandler.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/AbstractXMLHandler.java	Thu Aug  5 08:09:39 2004
@@ -85,7 +85,7 @@
             + "name=\"" + makeSafeAttribute( manager.getName() ) + "\" "
             + "description=\"" + makeSafeAttribute( manager.getDescription() ) + "\" "
             + "state-version=\"" + manager.getStateVersion() + "\" "
-            + "read-only=\"" + readOnly + "\">" );
+            + "batched-updates=\"true\" read-only=\"" + readOnly + "\">" );
         
         String childIndent = indent + INDENT;
         

Added: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/FavIconHandler.java
==============================================================================
--- (empty file)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/FavIconHandler.java	Thu Aug  5 08:09:39 2004
@@ -0,0 +1,89 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.excalibur.instrument.manager.http;
+
+import com.sun.image.codec.jpeg.JPEGCodec;
+import com.sun.image.codec.jpeg.JPEGEncodeParam;
+import com.sun.image.codec.jpeg.JPEGImageEncoder;
+
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+import org.apache.excalibur.instrument.manager.http.server.AbstractHTTPURLHandler;
+import org.apache.excalibur.instrument.manager.http.server.HTTPRedirect;
+import org.apache.excalibur.instrument.manager.http.server.URLCoder;
+import org.apache.excalibur.instrument.manager.DefaultInstrumentManager;
+import org.apache.excalibur.instrument.manager.InstrumentSampleDescriptor;
+import org.apache.excalibur.instrument.manager.InstrumentSampleSnapshot;
+import org.apache.excalibur.instrument.manager.NoSuchInstrumentSampleException;
+
+/**
+ * Serves up a favicon.ico file.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @version CVS $Revision: 1.9 $ $Date: 2004/03/06 14:01:28 $
+ * @since 4.1
+ */
+public class FavIconHandler
+    extends AbstractHTTPURLHandler
+{
+    /*---------------------------------------------------------------
+     * Constructors
+     *-------------------------------------------------------------*/
+    /**
+     * Creates a new FavIconHandler.
+     */
+    public FavIconHandler()
+    {
+        super( "/favicon.ico", CONTENT_TYPE_IMAGE_X_ICON,
+            InstrumentManagerHTTPConnector.ENCODING );
+    }
+    
+    /*---------------------------------------------------------------
+     * AbstractHandler Methods
+     *-------------------------------------------------------------*/
+    /**
+     * Handles the specified request.
+     *
+     * @param The full path being handled.
+     * @param parameters A Map of the parameters in the request.
+     * @param os The OutputStream to write the result to.
+     */
+    public void doGet( String path, Map parameters, OutputStream os )
+        throws IOException
+    {
+        String imageResource = "favicon.ico";
+        BufferedInputStream is =
+            new BufferedInputStream( getClass().getResourceAsStream( imageResource ) );
+        byte[] favIcon;
+        try {
+            favIcon = new byte[is.available()];
+            is.read( favIcon, 0, favIcon.length );
+        } finally {
+            is.close();
+        }
+        // Now write the image out to the client.
+        os.write( favIcon );
+    }
+}
+

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/InstrumentManagerHTTPConnector.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/InstrumentManagerHTTPConnector.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/InstrumentManagerHTTPConnector.java	Thu Aug  5 08:09:39 2004
@@ -166,9 +166,12 @@
         
         m_readOnly = configuration.getAttributeAsBoolean( "read-only", false );
         
+        String accessLogFile = configuration.getAttribute( "access-log", null );
+        
         m_httpServer = new HTTPServer( m_port, m_bindAddr );
         m_httpServer.enableLogging( getLogger().getChildLogger( "server" ) );
         m_httpServer.setInstrumentableName( "server" );
+        m_httpServer.setAccessLogFile( accessLogFile );
         addChildInstrumentable( m_httpServer );
     }
 
@@ -198,7 +201,11 @@
                 initAndRegisterHandler(
                     new XMLSampleLeaseHandler( m_manager, this ), nameBase + "sample-lease" );
                 initAndRegisterHandler(
+                    new XMLSampleLeasesHandler( m_manager, this ), nameBase + "sample-leases" );
+                initAndRegisterHandler(
                     new XMLCreateSampleHandler( m_manager, this ), nameBase + "create-sample" );
+                initAndRegisterHandler(
+                    new XMLCreateSamplesHandler( m_manager, this ), nameBase + "create-samples" );
                 initAndRegisterHandler(	new XMLGCHandler( m_manager ), nameBase + "gc" );
             }
         }
@@ -217,6 +224,7 @@
                 nameBase + "sample" );
             initAndRegisterHandler( new SampleChartHandler(
                 m_manager, m_chartWidth, m_chartHeight, m_antialias ), "sample-chart" );
+            initAndRegisterHandler( new FavIconHandler(), "favicon" );
             
             if ( !m_readOnly )
             {

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/SampleChartHandler.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/SampleChartHandler.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/SampleChartHandler.java	Thu Aug  5 08:09:39 2004
@@ -64,7 +64,6 @@
     /**
      * Creates a new SampleChartHandler.
      *
-     * @param path The path handled by this handler.
      * @param manager Reference to the instrument manager interface.
      * @param width Default image width.
      * @param height Default image height.

Added: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLCreateSamplesHandler.java
==============================================================================
--- (empty file)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLCreateSamplesHandler.java	Thu Aug  5 08:09:39 2004
@@ -0,0 +1,166 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.excalibur.instrument.manager.http;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+import org.apache.excalibur.instrument.manager.http.server.HTTPRedirect;
+import org.apache.excalibur.instrument.manager.DefaultInstrumentManager;
+import org.apache.excalibur.instrument.manager.InstrumentDescriptor;
+import org.apache.excalibur.instrument.manager.InstrumentSampleDescriptor;
+import org.apache.excalibur.instrument.manager.NoSuchInstrumentException;
+
+/**
+ * Handler which can be used to create multiple samples at once.
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @since 1.2
+ */
+public class XMLCreateSamplesHandler
+    extends AbstractXMLHandler
+{
+    /** Reference to the connector. */
+    private InstrumentManagerHTTPConnector m_connector;
+    
+    /*---------------------------------------------------------------
+     * Constructors
+     *-------------------------------------------------------------*/
+    /**
+     * Creates a new XMLCreateSamplesHandler.
+     *
+     * @param manager Reference to the DefaultInstrumentManager.
+     * @param connector The InstrumentManagerHTTPConnector.
+     */
+    public XMLCreateSamplesHandler( DefaultInstrumentManager manager,
+                                    InstrumentManagerHTTPConnector connector )
+    {
+        super( "/create-samples.xml", manager );
+        
+        m_connector = connector;
+    }
+    
+    /*---------------------------------------------------------------
+     * AbstractHTTPURLHandler Methods
+     *-------------------------------------------------------------*/
+    /**
+     * Handles the specified request.
+     *
+     * @param The full path being handled.
+     * @param parameters A Map of the parameters in the request.
+     * @param os The PrintWriter to write the result to.
+     */
+    public void doGet( String path, Map parameters, PrintWriter out )
+        throws IOException
+    {
+        String[] names = getParameters( parameters, "name" );
+        String[] descriptions = getParameters( parameters, "description" );
+        long[] intervals = getLongParameters( parameters, "interval", 0 );
+        int[] sizes = getIntegerParameters( parameters, "size", 0 );
+        long[] leases = getLongParameters( parameters, "lease", 0 );
+        int[] types = getIntegerParameters( parameters, "type", 0 );
+        boolean packed = ( getParameter( parameters, "packed", null ) != null );
+        
+        if ( names.length != descriptions.length )
+        {
+            throw new FileNotFoundException(
+                "The number of descriptions not equal to the number of names." );
+        }
+        if ( names.length != intervals.length )
+        {
+            throw new FileNotFoundException(
+                "The number of intervals not equal to the number of names." );
+        }
+        if ( names.length != sizes.length )
+        {
+            throw new FileNotFoundException(
+                "The number of sizes not equal to the number of names." );
+        }
+        if ( names.length != leases.length )
+        {
+            throw new FileNotFoundException(
+                "The number of leases not equal to the number of names." );
+        }
+        if ( names.length != types.length )
+        {
+            throw new FileNotFoundException(
+                "The number of types not equal to the number of names." );
+        }
+        
+        out.println( InstrumentManagerHTTPConnector.XML_BANNER );
+        if ( names.length > 0 )
+        {
+            outputLine( out, "", packed, "<samples>" );
+            
+            for ( int i = 0; i < names.length; i++ )
+            {
+                String name = names[i];
+                String description = descriptions[i];
+                long interval = intervals[i];
+                int size = sizes[i];
+                long lease = leases[i];
+                int type = types[i];
+                
+                InstrumentDescriptor desc;
+                try
+                {
+                    desc = getInstrumentManager().locateInstrumentDescriptor( name );
+                }
+                catch ( NoSuchInstrumentException e )
+                {
+                    // Not found, ignore.
+                    desc = null;
+                }
+                
+                if ( desc != null )
+                {
+                    // The instrument manager will do its own tests of the lease, but the
+                    //  restrictions on this connector may be stronger so they must be tested
+                    //  here as well.
+                    size = Math.max( 1, Math.min( size, m_connector.getMaxLeasedSampleSize() ) );
+                    lease = Math.max( 1, Math.min( lease, m_connector.getMaxLeasedSampleLease() ) );
+                    
+                    if ( getInstrumentManager().getLeaseSampleCount()
+                        >= m_connector.getMaxLeasedSamples() )
+                    {
+                        lease = 1;
+                    }
+                    
+                    // Register the new lease
+                    InstrumentSampleDescriptor sample =
+                        desc.createInstrumentSample( description, interval, size, lease, type );
+                    
+                    outputSample( out, sample, "  ", packed );
+                }
+            }
+            
+            outputLine( out, "", packed, "</samples>" );
+        }
+        else
+        {
+            outputLine( out, "", packed, "<samples/>" );
+        }
+    }
+            
+    /*---------------------------------------------------------------
+     * Methods
+     *-------------------------------------------------------------*/
+}
+

Added: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSampleLeasesHandler.java
==============================================================================
--- (empty file)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSampleLeasesHandler.java	Thu Aug  5 08:09:39 2004
@@ -0,0 +1,132 @@
+/* 
+ * Copyright 2002-2004 The Apache Software Foundation
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at 
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ * 
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.excalibur.instrument.manager.http;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+import org.apache.excalibur.instrument.manager.DefaultInstrumentManager;
+import org.apache.excalibur.instrument.manager.InstrumentSampleDescriptor;
+import org.apache.excalibur.instrument.manager.NoSuchInstrumentSampleException;
+
+/**
+ *
+ * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
+ * @since 1.2
+ */
+public class XMLSampleLeasesHandler
+    extends AbstractXMLHandler
+{
+    /** Reference to the connector. */
+    private InstrumentManagerHTTPConnector m_connector;
+    
+    /*---------------------------------------------------------------
+     * Constructors
+     *-------------------------------------------------------------*/
+    /**
+     * Creates a new XMLSampleLeasesHandler.
+     *
+     * @param manager Reference to the DefaultInstrumentManager.
+     * @param connector The InstrumentManagerHTTPConnector.
+     */
+    public XMLSampleLeasesHandler( DefaultInstrumentManager manager,
+                                   InstrumentManagerHTTPConnector connector )
+    {
+        super( "/sample-leases.xml", manager );
+        
+        m_connector = connector;
+    }
+    
+    /*---------------------------------------------------------------
+     * AbstractHTTPURLHandler Methods
+     *-------------------------------------------------------------*/
+    /**
+     * Handles the specified request.
+     *
+     * @param The full path being handled.
+     * @param parameters A Map of the parameters in the request.
+     * @param os The PrintWriter to write the result to.
+     */
+    public void doGet( String path, Map parameters, PrintWriter out )
+        throws IOException
+    {
+        String[] names = getParameters( parameters, "name" );
+        long[] leases = getLongParameters( parameters, "lease", 0 );
+        boolean packed = ( getParameter( parameters, "packed", null ) != null );
+        
+        if ( names.length != leases.length )
+        {
+            throw new FileNotFoundException(
+                "The number of leases values not equal to the number of names." );
+        }
+        
+        out.println( InstrumentManagerHTTPConnector.XML_BANNER );
+        if ( names.length > 0 )
+        {
+            outputLine( out, "", packed, "<samples>" );
+            
+            for ( int i = 0; i < names.length; i++ )
+            {
+                String name = names[i];
+                long lease = leases[i];
+                
+                InstrumentSampleDescriptor desc;
+                try
+                {
+                    desc = getInstrumentManager().locateInstrumentSampleDescriptor( name );
+                }
+                catch ( NoSuchInstrumentSampleException e )
+                {
+                    // Not found, ignore.
+                    desc = null;
+                }
+                
+                if ( desc != null )
+                {
+                    // The instrument manager will do its own tests of the lease, but the
+                    //  restrictions on this connector may be stronger so they must be tested
+                    //  here as well.
+                    lease = Math.max( 1, Math.min( lease, m_connector.getMaxLeasedSampleLease() ) );
+                    
+                    if ( getInstrumentManager().getLeaseSampleCount() >= m_connector.getMaxLeasedSamples() )
+                    {
+                        lease = 1;
+                    }
+                    
+                    // Renew the lease
+                    desc.extendLease( lease );
+                    
+                    outputSample( out, desc, "  ", packed );
+                }
+            }
+            
+            outputLine( out, "", packed, "</samples>" );
+        }
+        else
+        {
+            outputLine( out, "", packed, "<samples/>" );
+        }
+    }
+    
+    /*---------------------------------------------------------------
+     * Methods
+     *-------------------------------------------------------------*/
+}
+

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSnapshotsHandler.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSnapshotsHandler.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/XMLSnapshotsHandler.java	Thu Aug  5 08:09:39 2004
@@ -41,8 +41,7 @@
     /**
      * Creates a new XMLSnapshotsHandler.
      *
-     * @param path The path handled by this handler.
-     * @param contentType The content type.
+     * @param manager Reference to the DefaultInstrumentManager.
      */
     public XMLSnapshotsHandler( DefaultInstrumentManager manager )
     {
@@ -67,7 +66,7 @@
         boolean packed = ( getParameter( parameters, "packed", null ) != null );
         boolean compact = ( getParameter( parameters, "compact", null ) != null );
         
-        if ( ( baseTimes.length == 0 ) && ( baseTimes.length > 0 ) )
+        if ( ( baseTimes.length == 0 ) && ( names.length > 0 ) )
         {
             baseTimes = new long[baseTimes.length];
         }
@@ -106,7 +105,7 @@
             outputLine( out, "", packed, "<samples/>" );
         }
     }
-            
+    
     /*---------------------------------------------------------------
      * Methods
      *-------------------------------------------------------------*/

Added: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/favicon.ico
==============================================================================
Binary file. No diff available.

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/AbstractHTTPURLHandler.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/AbstractHTTPURLHandler.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/AbstractHTTPURLHandler.java	Thu Aug  5 08:09:39 2004
@@ -270,6 +270,26 @@
         }
     }
     
+    public int[] getIntegerParameters( Map params, String name, int defaultValue )
+    {
+        String[] values = getParameters( params, name );
+        int[] iValues = new int[values.length];
+        
+        for ( int i = 0; i < values.length; i++ )
+        {
+            try
+            {
+                iValues[i] = Integer.parseInt( values[i] );
+            }
+            catch ( NumberFormatException e )
+            {
+                iValues[i] = defaultValue;
+            }
+        }
+        
+        return iValues;
+    }
+    
     public long[] getLongParameters( Map params, String name, long defaultValue )
     {
         String[] values = getParameters( params, name );

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPServer.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPServer.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPServer.java	Thu Aug  5 08:09:39 2004
@@ -19,7 +19,9 @@
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileWriter;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.IOException;
@@ -28,6 +30,7 @@
 import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -52,9 +55,31 @@
     /** Optimized array of the handler list that lets us avoid synchronization */
     private HTTPURLHandler[] m_handlerArray;
     
+    /** Access log file name.  Null if not configured. */
+    private String m_accessLogFile;
+    
+    /** The currently open log file.  May be null. */
+    private File m_currentLogFile;
+    
+    /** The currently open log PrintWriter. */
+    private PrintWriter m_currentLogWriter;
+    
+    /** DateFormat used when generating log file names.  Only use when synchronized. */
+    private SimpleDateFormat m_dayFormat = new SimpleDateFormat( "yyyy-MM-dd" );
+    
+    /** DateFormat used when generating log entries.  Only use when synchronized. */
+    private SimpleDateFormat m_logTimeFormat = new SimpleDateFormat( "dd/MMM/yyyy:HH:mm:ss Z" );
+    
     /** Number of requests. */
     private CounterInstrument m_instrumentRequests;
     
+    /** Number of response bytes sent to the client.  Includes all bytes, not
+     *   only the content. */
+    private CounterInstrument m_instrumentResponseBytes;
+    
+    /** Number of request bytes received from the client. */
+    private CounterInstrument m_instrumentRequestBytes;
+    
     /*---------------------------------------------------------------
      * Constructors
      *-------------------------------------------------------------*/
@@ -70,11 +95,36 @@
         super( port, bindAddress );
         
         addInstrument( m_instrumentRequests = new CounterInstrument( "requests" ) );
+        addInstrument( m_instrumentResponseBytes = new CounterInstrument( "response-bytes" ) );
+        addInstrument( m_instrumentRequestBytes = new CounterInstrument( "request-bytes" ) );
     }
     
     /*---------------------------------------------------------------
      * AbstractSocketServer Methods
      *-------------------------------------------------------------*/
+    
+    /**
+     * Stops the server.
+     *
+     * @throws Exception If there are any problems stopping the component.
+     */
+    public void stop()
+        throws Exception
+    {
+        super.stop();
+        
+        // Close the logger if it is open.
+        synchronized( this )
+        {
+            if ( m_currentLogWriter != null )
+            {
+                m_currentLogWriter.close();
+                m_currentLogWriter = null;
+                m_currentLogFile = null;
+            }
+        }
+    }
+    
     /**
      * Handle a newly connected socket.  The implementation need not
      *  worry about closing the socket.
@@ -89,10 +139,12 @@
                 + Thread.currentThread().getName() );
         }
         
+        String ip = socket.getInetAddress().getHostAddress();
+        
         try
         {
             // As long as we have valid requests, keep the connection open.
-            while ( handleRequest( socket.getInputStream(), socket.getOutputStream() )
+            while ( handleRequest( socket.getInputStream(), socket.getOutputStream(), ip )
                 && !isStopping() )
             {
             }
@@ -120,6 +172,20 @@
     /*---------------------------------------------------------------
      * Methods
      *-------------------------------------------------------------*/
+    
+    /**
+     * Access log file name.  Null if not configured.
+     *  If the log file name contains the string "yyyy_mm_dd" then that
+     *  token will be replaced with the current day and the file will
+     *  be rolled each day at midnight.
+     *
+     * @param accessLogFile Name of the log file or null if disabled.
+     */
+    public void setAccessLogFile( String accessLogFile )
+    {
+        m_accessLogFile = accessLogFile;
+    }
+    
     /**
      * Registers a new HTTP URL Handler with the server.
      *
@@ -134,7 +200,91 @@
         }
     }
     
-    private boolean handleRequest( InputStream is, OutputStream os )
+    private void logAccessEvent( String ip,
+                                 String method,
+                                 String url,
+                                 int errorCode,
+                                 int contentLength,
+                                 String referrer,
+                                 String userAgent )
+    {
+        if ( m_accessLogFile == null )
+        {
+            return;
+        }
+        
+        Date now = new Date();
+        
+        synchronized( this )
+        {
+            File file;
+            int datePos = m_accessLogFile.indexOf( "yyyy_mm_dd" );
+            if ( datePos >= 0 )
+            {
+                StringBuffer sb = new StringBuffer();
+                if ( datePos > 0 )
+                {
+                    sb.append( m_accessLogFile.substring( 0, datePos ) );
+                }
+                sb.append( m_dayFormat.format( now ) );
+                if ( datePos + 10 < m_accessLogFile.length() )
+                {
+                    sb.append( m_accessLogFile.substring( datePos + 10 ) );
+                }
+                
+                file = new File( sb.toString() );
+            }
+            else
+            {
+                file = new File( m_accessLogFile );
+            }
+            
+            if ( ( m_currentLogFile == null ) || ( !m_currentLogFile.equals( file ) ) )
+            {
+                // Open a new log file.
+                if ( m_currentLogWriter != null )
+                {
+                    m_currentLogWriter.close();
+                }
+                try
+                {
+                    m_currentLogWriter = new PrintWriter( new FileWriter( file ) );
+                    m_currentLogFile = file;
+                }
+                catch ( IOException e )
+                {
+                    getLogger().warn( "Unable to open: " + m_currentLogFile );
+                    m_currentLogWriter = null;
+                    m_currentLogFile = null;
+                    return;
+                }
+            }
+            
+            // Now log the entry.
+            StringBuffer sb = new StringBuffer();
+            sb.append( ip );
+            sb.append( " - - [" );
+            sb.append( m_logTimeFormat.format( now ) );
+            sb.append( "] \"" );
+            sb.append( method );
+            sb.append( " " );
+            sb.append( url );
+            sb.append( "\" " );
+            sb.append( errorCode );
+            sb.append( " " );
+            sb.append( contentLength );
+            sb.append( " \"" );
+            sb.append( referrer );
+            sb.append( "\" \"" );
+            sb.append( userAgent );
+            sb.append( "\"" );
+            
+            m_currentLogWriter.println( sb.toString() );
+            m_currentLogWriter.flush();
+        }
+    }
+    
+    private boolean handleRequest( InputStream is, OutputStream os, String ip )
         throws IOException
     {
         // We only support the GET method and know nothing of headers so this is easy.
@@ -150,14 +300,40 @@
             // EOF
             return false;
         }
-        
-        // Read any headers until we get a blank line
-        String header;
-        do
+            
+        String referrer = "-";
+        String userAgent = "-";
+        int requestBytes = request.getBytes().length + 1;
+        try
         {
-            header = r.readLine();
+            // Read any headers until we get a blank line
+            String header;
+            do
+            {
+                header = r.readLine();
+                if ( header != null )
+                {
+                    if ( header.startsWith( "User-Agent: " ) )
+                    {
+                        userAgent = header.substring( 12 );
+                    }
+                    else if ( header.startsWith( "Referer: " ) )
+                    {
+                        referrer = header.substring( 9 );
+                    }
+                    
+                    requestBytes += header.getBytes().length + 1;
+                }
+            }
+            while ( ( header != null ) && ( header.length() > 0 ) );
+        }
+        finally
+        {
+            if ( requestBytes > 0 )
+            {
+                m_instrumentRequestBytes.increment( requestBytes );
+            }
         }
-        while ( ( header != null ) && ( header.length() > 0 ) );
         
         if ( getLogger().isDebugEnabled() )
         {
@@ -171,12 +347,15 @@
         ByteArrayOutputStream hbos = new ByteArrayOutputStream();
         PrintWriter out = new PrintWriter( hbos );
         
+        String method = "ERROR";
+        String url = "";
+        
         // Parse the header to make sure it is valid.
         StringTokenizer st = new StringTokenizer( request, " " );
         if ( st.countTokens() == 3 )
         {
-            String method = st.nextToken();
-            String url = st.nextToken();
+            method = st.nextToken();
+            url = st.nextToken();
             String version = st.nextToken();
             
             if ( method.equals( "GET" ) && version.startsWith( "HTTP/" ) )
@@ -272,7 +451,8 @@
                             
                             // Write the contents of the headers.
                             out.flush();
-                            os.write( hbos.toByteArray() );
+                            byte[] responseBytes = hbos.toByteArray();
+                            os.write( responseBytes );
                             
                             // Write out the actual data directly to the stream.
                             os.write( contents, 0, contents.length );
@@ -280,6 +460,13 @@
                             // Flush the stream and we are done.
                             os.flush();
                             
+                            // Record the total number of bytes sent to the client.
+                            m_instrumentResponseBytes.increment(
+                                responseBytes.length + contents.length );
+                            
+                            // Log the request.
+                            logAccessEvent( ip, method, url, 302, contents.length, referrer, userAgent );
+                            
                             // Do not close the output stream as it may be reused.
                             
                             return true;
@@ -313,7 +500,8 @@
                             
                             // Write the contents of the headers.
                             out.flush();
-                            os.write( hbos.toByteArray() );
+                            byte[] responseBytes = hbos.toByteArray();
+                            os.write( responseBytes );
                             
                             // Write out the actual data directly to the stream.
                             os.write( contents, 0, contents.length );
@@ -321,6 +509,13 @@
                             // Flush the stream and we are done.
                             os.flush();
                             
+                            // Record the total number of bytes sent to the client.
+                            m_instrumentResponseBytes.increment(
+                                responseBytes.length + contents.length );
+                            
+                            // Log the request.
+                            logAccessEvent( ip, method, url, 200, contents.length, referrer, userAgent );
+                            
                             // Do not close the output stream as it may be reused.
                             
                             return true;
@@ -359,8 +554,15 @@
         
         // Write the contents of the headers.
         out.flush();
-        os.write( hbos.toByteArray() );
+        byte[] responseBytes = hbos.toByteArray();
+        os.write( responseBytes );
         os.flush();
+        
+        // Record the total number of bytes sent to the client.
+        m_instrumentResponseBytes.increment( responseBytes.length );
+        
+        // Log the request.
+        logAccessEvent( ip, method, url, 404, 0, referrer, userAgent );
         
         return false;
     }

Modified: excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPURLHandler.java
==============================================================================
--- excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPURLHandler.java	(original)
+++ excalibur/trunk/containerkit/instrument/mgr-http/src/java/org/apache/excalibur/instrument/manager/http/server/HTTPURLHandler.java	Thu Aug  5 08:09:39 2004
@@ -30,9 +30,10 @@
  */
 public interface HTTPURLHandler
 {
-    String CONTENT_TYPE_TEXT_HTML  = "text/html";
-    String CONTENT_TYPE_TEXT_XML   = "text/xml";
-    String CONTENT_TYPE_IMAGE_JPEG = "image/jpeg";
+    String CONTENT_TYPE_TEXT_HTML    = "text/html";
+    String CONTENT_TYPE_TEXT_XML     = "text/xml";
+    String CONTENT_TYPE_IMAGE_JPEG   = "image/jpeg";
+    String CONTENT_TYPE_IMAGE_X_ICON = "image/x-icon";
     
     /**
      * Returns the path handled by this handler.

---------------------------------------------------------------------
To unsubscribe, e-mail: scm-unsubscribe@excalibur.apache.org
For additional commands, e-mail: scm-help@excalibur.apache.org