cvs commit: spice/components/netserve/src/test/org/jcomponent/netserve/sockets/impl SocketTestCase.java

[email protected] Wed, 19 Nov 2003 18:25:07 -0600
Newsgroups gmane.comp.java.spice.cvs
Message-ID <[email protected]>
mauro       2003/11/19 18:25:07

  Modified:    components/netserve project.xml
               components/netserve/xdocs index.xml
  Added:       components/netserve/src/java/org/codehaus/spice/netserve/sockets/impl
                        DefaultSocketFactory.java
                        DefaultServerSocketFactory.java
                        DefaultServerSocketFactory.xinfo
                        DefaultSocketFactory.xinfo
               components/netserve/src/java/org/codehaus/spice/netserve/connection/impl
                        DNAAcceptorManager.java PicoAcceptorManager.java
                        AcceptorMonitor.java AcceptorManager-schema.xml
                        DefaultAcceptorManager.java
                        AbstractLoggingAcceptorMonitor.java
                        DNAAcceptorMonitor.java AcceptorConfig.java
                        NullAcceptorMonitor.java ConnectionAcceptor.java
               components/netserve/src/test/org/codehaus/spice/netserve/connection/impl
                        AcceptorConfigTestCase.java
                        DNAAcceptorMonitorTestCase.java
                        DNAAcceptorManagerTestCase.java
                        PicoAcceptorManagerTestCase.java
                        ClosingSocketConnectionHandler.java
                        RecordingAcceptorMonitor.java
                        MockSocketConnectionHandler.java
                        ExceptOnCloseServerSocket.java
                        ExceptOnAcceptServerSocket.java
                        ConnectionAcceptorTestCase.java
                        BlockingServerSocket.java
                        DefaultAcceptorManagerTestCase.java
               components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers
                        RequestHandlerTestCase.java MockRequestHandler.java
                        ExceptingRequestHandler.java
                        DelegatingRequestHandlerTestCase.java
                        ManagedRequestHandlerTestCase.java
                        MockThreadPool.java
                        ThreadPerRequestHandlerTestCase.java
                        ExceptionOnCloseSocket.java
                        DelayingRequestHandler.java
                        MockManagedRequestHandler.java
                        MockThreadControl.java RequestManager.java
               components/netserve/src/java/org/codehaus/spice/netserve/connection/handlers
                        ThreadPerRequestHandler.java
                        DelegatingRequestHandler.java
                        AbstractRequestHandler.java
                        ManagedRequestHandler.java
               components/netserve/src/java/org/codehaus/spice/netserve/connection
                        RequestHandler.java SocketAcceptorManager.java
               components/netserve/src/java/org/codehaus/spice/netserve/sockets
                        ServerSocketFactory.java SocketFactory.java
               components/netserve/src/test/org/codehaus/spice/netserve/sockets/impl
                        SocketTestCase.java
  Removed:     components/netserve/src/test/org/jcomponent/netserve/connection/impl
                        DefaultAcceptorManagerTestCase.java
                        PicoAcceptorManagerTestCase.java
                        MockSocketConnectionHandler.java
                        RecordingAcceptorMonitor.java
                        ConnectionAcceptorTestCase.java
                        AcceptorConfigTestCase.java
                        ClosingSocketConnectionHandler.java
                        BlockingServerSocket.java
                        ExceptOnCloseServerSocket.java
                        DNAAcceptorMonitorTestCase.java
                        DNAAcceptorManagerTestCase.java
                        ExceptOnAcceptServerSocket.java
               components/netserve/src/java/org/jcomponent/netserve/connection
                        RequestHandler.java SocketAcceptorManager.java
               components/netserve/src/java/org/jcomponent/netserve/connection/impl
                        PicoAcceptorManager.java AcceptorManager-schema.xml
                        DNAAcceptorManager.java DNAAcceptorMonitor.java
                        ConnectionAcceptor.java AcceptorConfig.java
                        AbstractLoggingAcceptorMonitor.java
                        AcceptorMonitor.java NullAcceptorMonitor.java
                        DefaultAcceptorManager.java
               components/netserve/src/test/org/jcomponent/netserve/connection/handlers
                        MockThreadPool.java
                        ManagedRequestHandlerTestCase.java
                        DelegatingRequestHandlerTestCase.java
                        MockRequestHandler.java DelayingRequestHandler.java
                        ThreadPerRequestHandlerTestCase.java
                        RequestHandlerTestCase.java
                        MockManagedRequestHandler.java
                        ExceptingRequestHandler.java MockThreadControl.java
                        RequestManager.java ExceptionOnCloseSocket.java
               components/netserve/src/java/org/jcomponent/netserve/sockets
                        SocketFactory.java ServerSocketFactory.java
               components/netserve/src/java/org/jcomponent/netserve/sockets/impl
                        DefaultServerSocketFactory.xinfo
                        DefaultSocketFactory.java
                        DefaultServerSocketFactory.java
                        DefaultSocketFactory.xinfo
               components/netserve/src/java/org/jcomponent/netserve/connection/handlers
                        AbstractRequestHandler.java
                        DelegatingRequestHandler.java
                        ThreadPerRequestHandler.java
                        ManagedRequestHandler.java
               components/netserve/src/test/org/jcomponent/netserve/sockets/impl
                        SocketTestCase.java
  Log:
  Renamed org.jcomponent -> org.codehaus.spice
  
  Revision  Changes    Path
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/impl/DefaultSocketFactory.java
  
  Index: DefaultSocketFactory.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.sockets.impl;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.Socket;
  import org.codehaus.spice.netserve.sockets.SocketFactory;
  
  /**
   * A SocketFactory that creates vanilla sockets.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:04 $
   * @dna.component
   * @dna.service type="SocketFactory"
   */
  public class DefaultSocketFactory
      implements SocketFactory
  {
      /**
       * Create a socket that connects to specified remote address.
       *
       * @param address the remote address
       * @param port the remote port
       * @return the socket connected to remote address
       * @throws IOException if unable to create socket
       */
      public Socket createSocket( final InetAddress address, final int port )
          throws IOException
      {
          return new Socket( address, port );
      }
  
      /**
       * Create a socket that connects to specified remote address and
       * originates from specified local address.
       *
       * @param address the remote address
       * @param port the remote port
       * @param localAddress the local address
       * @param localPort the local port
       * @return the socket connected to remote address
       * @throws IOException if unable to create socket
       */
      public Socket createSocket( final InetAddress address,
                                  final int port,
                                  final InetAddress localAddress,
                                  final int localPort )
          throws IOException
      {
          return new Socket( address, port, localAddress, localPort );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/impl/DefaultServerSocketFactory.java
  
  Index: DefaultServerSocketFactory.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.sockets.impl;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.ServerSocket;
  import org.codehaus.spice.netserve.sockets.ServerSocketFactory;
  
  /**
   * Factory implementation for vanilla TCP sockets.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:04 $
   * @dna.component
   * @dna.service type="ServerSocketFactory"
   */
  public class DefaultServerSocketFactory
      implements ServerSocketFactory
  {
      /**
       * Creates a socket on specified port.
       *
       * @param port the port (0 indicates any available port)
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      public ServerSocket createServerSocket( final int port )
          throws IOException
      {
          return new ServerSocket( port );
      }
  
      /**
       * Creates a socket on specified port with a specified backlog.
       *
       * @param port the port (0 indicates any available port)
       * @param backlog the backlog
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      public ServerSocket createServerSocket( int port, int backlog )
          throws IOException
      {
          return new ServerSocket( port, backlog );
      }
  
      /**
       * Creates a socket on a particular network interface on specified port
       * with a specified backlog.
       *
       * @param port the port (0 indicates any available port)
       * @param backlog the backlog
       * @param address the network interface to bind to.
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      public ServerSocket createServerSocket( int port, int backlog, InetAddress address )
          throws IOException
      {
          return new ServerSocket( port, backlog, address );
      }
  }
  
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/impl/DefaultServerSocketFactory.xinfo
  
  Index: DefaultServerSocketFactory.xinfo
  ===================================================================
  <?xml version="1.0"?>
  <!DOCTYPE blockinfo PUBLIC "-//PHOENIX/Block Info DTD Version 1.0//EN"
                    "http://jakarta.apache.org/avalon/dtds/phoenix/blockinfo_1_0.dtd">
  <blockinfo>
      <block>
          <version>1.0</version>
      </block>
      <services>
          <service name="org.codehaus.spice.netserve.sockets.ServerSocketFactory"/>
      </services>
  </blockinfo>
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/impl/DefaultSocketFactory.xinfo
  
  Index: DefaultSocketFactory.xinfo
  ===================================================================
  <?xml version="1.0"?>
  <!DOCTYPE blockinfo PUBLIC "-//PHOENIX/Block Info DTD Version 1.0//EN"
                    "http://jakarta.apache.org/avalon/dtds/phoenix/blockinfo_1_0.dtd">
  <blockinfo>
      <block>
          <version>1.0</version>
      </block>
      <services>
          <service name="org.codehaus.spice.netserve.sockets.SocketFactory"/>
      </services>
  </blockinfo>
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/DNAAcceptorManager.java
  
  Index: DNAAcceptorManager.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import org.jcontainer.dna.Configuration;
  import org.jcontainer.dna.ConfigurationException;
  import org.jcontainer.dna.Active;
  import org.jcontainer.dna.Configurable;
  import org.jcontainer.dna.LogEnabled;
  import org.jcontainer.dna.Logger;
  import org.codehaus.spice.netserve.connection.impl.DefaultAcceptorManager;
  
  /**
   * A DNA compliant implementation of AcceptorManager.
   *
   * <p>The component takes a single configuration parameter;
   * "shutdownTimeout". This specifies the amount of time to wait
   * while waiting for connections to shutdown gracefully. A
   * sample configuration follows;</p>
   * <pre>
   *  &lt;!-- wait 200ms for connections to gracefully shutdown --&gt;
   *  &lt;shutdownTimeout&gt;200&lt;/shutdownTimeout&gt;
   * </pre>
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   * @dna.component
   * @dna.service type="org.codehaus.spice.netserve.connection.SocketAcceptorManager"
   * @see org.codehaus.spice.netserve.connection.impl.DefaultAcceptorManager
   */
  public class DNAAcceptorManager
     extends DefaultAcceptorManager
     implements LogEnabled, Configurable, Active
  {
     /**
      * @dna.logger
      */
     public void enableLogging( final Logger logger )
     {
        setMonitor( new DNAAcceptorMonitor( logger ) );
     }
  
     /**
      * @dna.configuration type="http://relaxng.org/ns/structure/1.0"
      *    location="AcceptorManager-schema.xml"
      */
     public void configure( final Configuration configuration )
        throws ConfigurationException
     {
        setShutdownTimeout( configuration.getChild( "shutdownTimeout" ).getValueAsInteger( 0 ) );
     }
  
     /**
      * Nothing to do to initial AcceptorManager.
      */
     public void initialize()
        throws Exception
     {
     }
  
     /**
      * Shutdown all connections.
      */
     public void dispose()
     {
        shutdownAcceptors();
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/PicoAcceptorManager.java
  
  Index: PicoAcceptorManager.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import org.codehaus.spice.netserve.connection.impl.AcceptorMonitor;
  import org.codehaus.spice.netserve.connection.impl.DefaultAcceptorManager;
  
  /**
   * A Pico compliant implementation of AcceptorManager.
   */
  public class PicoAcceptorManager
     extends DefaultAcceptorManager
  {
     /**
      * Create instance with default timeout and monitor.
      */
     public PicoAcceptorManager()
     {
     }
  
     /**
      * Create instance with default monitor.
      *
      * @param shutdownTimeout the timeout
      */
     public PicoAcceptorManager( final int shutdownTimeout )
     {
        setShutdownTimeout( shutdownTimeout );
     }
  
     /**
      * Create instance with default timeout.
      *
      * @param monitor the monitor
      */
     public PicoAcceptorManager( final AcceptorMonitor monitor )
     {
        setMonitor( monitor );
     }
  
     /**
      * Create instance specifying both timeout and monitor.
      *
      * @param shutdownTimeout the timeout
      * @param monitor the monitor
      */
     public PicoAcceptorManager( final int shutdownTimeout,
                                 final AcceptorMonitor monitor )
     {
        setShutdownTimeout( shutdownTimeout );
        setMonitor( monitor );
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/AcceptorMonitor.java
  
  Index: AcceptorMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  
  /**
   * Monitor used to monitor events in the AcceptorManager.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public interface AcceptorMonitor
  {
      /**
       * Aceptor create with name for specified socket.
       *
       * @param name the acceptor name
       * @param serverSocket the socket
       */
      void acceptorCreated( String name, ServerSocket serverSocket );
  
      /**
       * About to close down acceptor and stop listening for
       * connections.
       *
       * @param name the acceptor name
       * @param serverSocket the socket
       */
      void acceptorClosing( String name, ServerSocket serverSocket );
  
      /**
       * Listening for connection attempts in acceptor.
       *
       * @param name the acceptor name
       * @param serverSocket the socket
       */
      void serverSocketListening( String name, ServerSocket serverSocket );
  
      /**
       * There was an error accepting client connections.
       *
       * @param name the name of acceptor
       * @param ioe the exception
       */
      void errorAcceptingConnection( String name, IOException ioe );
  
      /**
       * There was an error closing server socket.
       *
       * @param name the name of acceptor
       * @param ioe the exception
       */
      void errorClosingServerSocket( String name, IOException ioe );
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/AcceptorManager-schema.xml
  
  Index: AcceptorManager-schema.xml
  ===================================================================
  <?xml version="1.0"?>
  <element
      name="root"
      xmlns="http://relaxng.org/ns/structure/1.0"
      datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
      <interleave>
          <element name="shutdownTimeout"><data type="integer"/></element>
      </interleave>
  </element>
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/DefaultAcceptorManager.java
  
  Index: DefaultAcceptorManager.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.ServerSocket;
  import java.util.Hashtable;
  import java.util.Map;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  import org.codehaus.spice.netserve.connection.SocketAcceptorManager;
  import org.codehaus.spice.netserve.connection.impl.AcceptorConfig;
  import org.codehaus.spice.netserve.connection.impl.AcceptorMonitor;
  import org.codehaus.spice.netserve.connection.impl.ConnectionAcceptor;
  
  /**
   * Default implementation of SocketAcceptorManager that uses
   * a thread per acceptor approach.
   *
   * <p>Note that on some OS/JVM combinations <tt>soTimeout</tt> must
   * be set to non-0 value or else the ServerSocket will never get out
   * of accept() system call and we wont be able to shutdown the server
   * socket properly. However it can introduce performance problems if
   * constantly timing out. </p>
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class DefaultAcceptorManager
      implements SocketAcceptorManager
  {
      /**
       * The map of name->acceptor.
       */
      private final Map m_acceptors = new Hashtable();
  
      /**
       * The monitor that receives notifications of Connection events
       */
      private AcceptorMonitor m_monitor = NullAcceptorMonitor.MONITOR;
  
      /**
       * Value that we are to set SO_TIMEOUT to if the user
       * has not already set the timeout. Defaults to 1000 (1s timeout).
       */
      private int m_soTimeout = 1000;
  
      /**
       * Set to the number of milliseconds that we will wait
       * for a connection to shutdown gracefully. Defaults to 0
       * which indicates indefinite wait.
       */
      private int m_shutdownTimeout;
  
      /**
       * Set the AcceptorMonitor that receives events when changes occur.
       *
       * @param monitor the AcceptorMonitor that receives events when
       *        changes occur.
       */
      public void setMonitor( final AcceptorMonitor monitor )
      {
          m_monitor = monitor;
      }
  
      /**
       * Set the value that we are to set SO_TIMEOUT to if the user
       * has not already set the timeout. Defaults to 1000 (1s timeout).
       *
       * @param soTimeout the timeout value
       */
      public void setSoTimeout( final int soTimeout )
      {
          m_soTimeout = soTimeout;
      }
  
      /**
       * Set timeout for shutting down handlers.
       * The timeout defaults to 0 which means wait indefinetly.
       *
       * @param shutdownTimeout the timeout
       */
      public void setShutdownTimeout( final int shutdownTimeout )
      {
          m_shutdownTimeout = shutdownTimeout;
      }
  
      /**
       * Return the shutdownTimeout.
       *
       * @return the shutdownTimeout
       */
      protected int getShutdownTimeout()
      {
          return m_shutdownTimeout;
      }
  
      /**
       * Dispose the ConnectionManager which involves shutting down all
       * the connected acceptors.
       */
      public void shutdownAcceptors()
      {
          final String[] names;
          synchronized( m_acceptors )
          {
              names = (String[])m_acceptors.keySet().toArray( new String[ 0 ] );
          }
          for( int i = 0; i < names.length; i++ )
          {
              disconnect( names[ i ] );
          }
      }
  
      /**
       * Start accepting connections from a socket and passing connections
       * to specified handler.
       *
       * @param name the name of connection. This serves as a key used to
       *        shutdown acceptor.
       * @param socket the ServerSocket from which connections are accepted
       * @throws java.lang.Exception if unable to initiate connection management. This could
       *         be due to the key already being used for another acceptor,
       *        the serversocket being closed, the handler being null etc.
       */
      public void connect( final String name,
                           final ServerSocket socket,
                           final RequestHandler handler )
          throws Exception
      {
          if( null == name )
          {
              throw new NullPointerException( "name" );
          }
          if( null == socket )
          {
              throw new NullPointerException( "socket" );
          }
          if( null == handler )
          {
              throw new NullPointerException( "handler" );
          }
  
          if( 0 == socket.getSoTimeout() )
          {
              socket.setSoTimeout( m_soTimeout );
          }
  
          final ConnectionAcceptor acceptor;
          synchronized( m_acceptors )
          {
              if( isConnected( name ) )
              {
                  final String message =
                      "Connection already exists with name " + name;
                  throw new IllegalArgumentException( message );
              }
  
              final AcceptorConfig config = new AcceptorConfig( name, socket, handler );
              acceptor = new ConnectionAcceptor( config, getMonitor() );
              m_acceptors.put( name, acceptor );
          }
  
          final Thread thread =
              new Thread( acceptor, "Acceptor[" + name + "]" );
          thread.start();
          while( !acceptor.hasStarted() )
          {
              Thread.sleep( 5 );
          }
      }
  
      /**
       * Return true if acceptor with specified name exists.
       *
       * @param name the name
       * @return true if acceptor with specified name exists.
       */
      public boolean isConnected( final String name )
      {
          return m_acceptors.containsKey( name );
      }
  
      /**
       * This shuts down the acceptor and the associated ServerSocket.
       *
       * @param name the name of connection
       * @throws java.lang.IllegalArgumentException if no connection with specified name
       */
      public void disconnect( final String name )
      {
          final ConnectionAcceptor acceptor =
              (ConnectionAcceptor)m_acceptors.remove( name );
          if( null == acceptor )
          {
              final String message = "No connection with name " + name;
              throw new IllegalArgumentException( message );
          }
  
          acceptor.close( getShutdownTimeout() );
      }
  
      /**
       * Return the monitor used by manager.
       *
       * @return the monitor used by manager.
       */
      protected AcceptorMonitor getMonitor()
      {
          return m_monitor;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/AbstractLoggingAcceptorMonitor.java
  
  Index: AbstractLoggingAcceptorMonitor.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  
  /**
   * An abstract monitor that writes out messages
   * for acceptor events. Need to subclass and implement
   * methods to write out log messages.
   */
  public abstract class AbstractLoggingAcceptorMonitor
     implements AcceptorMonitor
  {
     /**
      * @see AcceptorMonitor#acceptorCreated
      */
     public void acceptorCreated( final String name,
                                  final ServerSocket serverSocket )
     {
        final String message =
           "Creating Acceptor " + name + " on " +
           serverSocket.getInetAddress().getHostAddress() + ":" +
           serverSocket.getLocalPort() + ".";
        info( message );
     }
  
     /**
      * @see AcceptorMonitor#acceptorClosing
      */
     public void acceptorClosing( final String name,
                                  final ServerSocket serverSocket )
     {
        final String message = "Closing Acceptor " + name + ".";
        info( message );
     }
  
     /**
      * @see AcceptorMonitor#serverSocketListening
      */
     public void serverSocketListening( final String name,
                                        final ServerSocket serverSocket )
     {
        if ( isDebugEnabled() )
        {
           final String message =
              "About to call accept() on ServerSocket '" + name + "'.";
           debug( message );
        }
     }
  
     /**
      * @see AcceptorMonitor#errorAcceptingConnection
      */
     public void errorAcceptingConnection( final String name,
                                           final IOException ioe )
     {
        warn( "Error Accepting connection on " + name, ioe );
     }
  
     /**
      * @see AcceptorMonitor#errorClosingServerSocket
      */
     public void errorClosingServerSocket( final String name,
                                           final IOException ioe )
     {
        warn( "Error Closing Server Socket " + name, ioe );
     }
  
     /**
      * Return true if debug logging enabled.
      *
      * @return true if debug logging enabled.
      */
     protected abstract boolean isDebugEnabled();
  
     /**
      * Write out debug message.
      *
      * @param message the message
      */
     protected abstract void debug( String message );
  
     /**
      * Write out info message.
      *
      * @param message the message
      */
     protected abstract void info( String message );
  
     /**
      * Write out warn message.
      *
      * @param message the message
      * @param e the warnings cause
      */
     protected abstract void warn( String message, Exception e );
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/DNAAcceptorMonitor.java
  
  Index: DNAAcceptorMonitor.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import org.jcontainer.dna.Logger;
  import org.codehaus.spice.netserve.connection.impl.AbstractLoggingAcceptorMonitor;
  
  /**
   * AcceptorMonitor that writes out messages to DNA Logger.
   */
  public class DNAAcceptorMonitor
     extends AbstractLoggingAcceptorMonitor
  {
     /**
      * The associated DNA Logger.
      */
     private final Logger m_logger;
  
     /**
      * Create AcceptorMonitor that writes to DNA Logger.
      *
      * @param logger the logger
      */
     public DNAAcceptorMonitor( final Logger logger )
     {
        if ( null == logger )
        {
           throw new NullPointerException( "logger" );
        }
        m_logger = logger;
     }
  
     /**
      * @see AbstractLoggingAcceptorMonitor#isDebugEnabled
      */
     protected boolean isDebugEnabled()
     {
        return getLogger().isDebugEnabled();
     }
  
     /**
      * @see AbstractLoggingAcceptorMonitor#debug
      */
     protected void debug( final String message )
     {
        getLogger().debug( message );
     }
  
     /**
      * @see AbstractLoggingAcceptorMonitor#info
      */
     protected void info( final String message )
     {
        getLogger().info( message );
     }
  
     /**
      * @see AbstractLoggingAcceptorMonitor#warn
      */
     protected void warn( final String message,
                          final Exception e )
     {
        getLogger().warn( message, e );
     }
  
     /**
      * Return the logger.
      *
      * @return the logger
      */
     protected Logger getLogger()
     {
        return m_logger;
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/AcceptorConfig.java
  
  Index: AcceptorConfig.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.ServerSocket;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   * A utility class that contains acceptor configuration.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class AcceptorConfig
  {
      /**
       * The name of the connection.
       */
      private final String m_name;
  
      /**
       * The ServerSocket that we are accepting connections from.
       */
      private final ServerSocket m_serverSocket;
  
      /**
       * The ConnectionHandlerManager that we create ConnectionHandlers from.
       */
      private final RequestHandler m_handler;
  
      /**
       * Create the acceptor.
       *
       * @param name the name that connection was registered using
       * @param serverSocket the ServerSocket that used to accept connections
       * @param handler the handler for new connections
       */
      AcceptorConfig( final String name,
                      final ServerSocket serverSocket,
                      final RequestHandler handler )
      {
          if( null == name )
          {
              throw new NullPointerException( "name" );
          }
          if( null == serverSocket )
          {
              throw new NullPointerException( "serverSocket" );
          }
          if( null == handler )
          {
              throw new NullPointerException( "handler" );
          }
          m_name = name;
          m_serverSocket = serverSocket;
          m_handler = handler;
      }
  
      /**
       * Return the name acceptor registered under.
       *
       * @return the name acceptor registered under.
       */
      String getName()
      {
          return m_name;
      }
  
      /**
       * Return the socket that connections accepted from.
       *
       * @return the socket that connections accepted from.
       */
      ServerSocket getServerSocket()
      {
          return m_serverSocket;
      }
  
      /**
       * Return the handler the connections are handled by.
       *
       * @return the handler the connections are handled by.
       */
      RequestHandler getHandler()
      {
          return m_handler;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/NullAcceptorMonitor.java
  
  Index: NullAcceptorMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  
  import org.codehaus.spice.netserve.connection.impl.AcceptorMonitor;
  
  /**
   * A noop monitor.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class NullAcceptorMonitor
      implements AcceptorMonitor
  {
      /**
       * Add constant for instance of Null Monitor.
       */
      public static final NullAcceptorMonitor MONITOR = new NullAcceptorMonitor();
  
      /**
       * @see AcceptorMonitor#acceptorCreated
       */
      public void acceptorCreated( final String name,
                                   final ServerSocket serverSocket )
      {
      }
  
      /**
       * @see AcceptorMonitor#acceptorClosing
       */
      public void acceptorClosing( final String name,
                                   final ServerSocket serverSocket )
      {
      }
  
      /**
       * @see AcceptorMonitor#serverSocketListening
       */
      public void serverSocketListening( final String name,
                                         final ServerSocket serverSocket )
      {
      }
  
      /**
       * @see AcceptorMonitor#errorAcceptingConnection
       */
      public void errorAcceptingConnection( final String name,
                                            final IOException ioe )
      {
      }
  
      /**
       * @see AcceptorMonitor#errorClosingServerSocket
       */
      public void errorClosingServerSocket( final String name,
                                            final IOException ioe )
      {
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/impl/ConnectionAcceptor.java
  
  Index: ConnectionAcceptor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.io.InterruptedIOException;
  import java.net.Socket;
  
  import org.codehaus.spice.netserve.connection.impl.AcceptorConfig;
  import org.codehaus.spice.netserve.connection.impl.AcceptorMonitor;
  
  /**
   * A helper class that manages acceptor for a single ServerSocket.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ConnectionAcceptor
      implements Runnable
  {
      /**
       * The configuration for acceptor.
       */
      private final AcceptorConfig m_config;
  
      /**
       * The AcceptorMonitor for event notification.
       */
      private final AcceptorMonitor m_monitor;
  
      private boolean m_started;
  
      private boolean m_active;
  
      /**
       * The thread in which the main accept loop is running.
       * Setup at start of thread and set to null to shutdown
       * acceptor.
       */
      private Thread m_thread;
  
      /**
       * Create the acceptor.
       *
       * @param config the config for acceptor
       * @param monitor the monitor
       */
      ConnectionAcceptor( final AcceptorConfig config,
                          final AcceptorMonitor monitor )
      {
          if( null == config )
          {
              throw new NullPointerException( "config" );
          }
          if( null == monitor )
          {
              throw new NullPointerException( "monitor" );
          }
          m_config = config;
          m_monitor = monitor;
          m_monitor.acceptorCreated( m_config.getName(),
                                     m_config.getServerSocket() );
      }
  
      /**
       * Return true if acceptor has started.
       *
       * @return true if acceptor has started.
       */
      synchronized boolean hasStarted()
      {
          return m_started;
      }
  
      /**
       * Shutdown the acceptor.
       */
      void close( final long timeout )
      {
          synchronized( this )
          {
              m_active = false;
              m_monitor.acceptorClosing( m_config.getName(),
                                         m_config.getServerSocket() );
              m_thread.interrupt();
              try
              {
                  wait( timeout );
              }
              catch( InterruptedException e )
              {
                  //ignore
              }
          }
      }
  
      /**
       * The main accept & handle loop for acceptor.
       */
      public void run()
      {
          //Setup thread to indicate that we are currently running
          synchronized( this )
          {
              m_started = true;
              m_active = true;
              m_thread = Thread.currentThread();
          }
          while( isRunning() )
          {
              m_monitor.serverSocketListening( m_config.getName(),
                                               m_config.getServerSocket() );
              try
              {
                  final Socket socket = m_config.getServerSocket().accept();
                  if( isRunning() )
                  {
                      m_config.getHandler().handleConnection( socket );
                  }
                  else
                  {
                      try
                      {
                          socket.close();
                      }
                      catch( final Exception e )
                      {
                          //Ignore
                      }
                  }
              }
              catch( final InterruptedIOException iioe )
              {
                  //Consume exception
              }
              catch( final IOException ioe )
              {
                  m_monitor.errorAcceptingConnection( m_config.getName(), ioe );
              }
          }
  
          shutdownServerSocket();
          synchronized( this )
          {
              m_thread = null;
              notifyAll();
          }
      }
  
      /**
       * Utility method to shutdown serverSocket.
       */
      void shutdownServerSocket()
      {
          try
          {
              m_config.getServerSocket().close();
          }
          catch( final IOException ioe )
          {
              m_monitor.errorClosingServerSocket( m_config.getName(), ioe );
          }
      }
  
      /**
       * Return true if the acceptor is currently running.
       *
       * @return true if the acceptor is currently running.
       */
      synchronized boolean isRunning()
      {
          return m_active;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/AcceptorConfigTestCase.java
  
  Index: AcceptorConfigTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.ServerSocket;
  
  import junit.framework.TestCase;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class AcceptorConfigTestCase
     extends TestCase
  {
     public void testCreation()
        throws Exception
     {
        final String name = "name";
        final ServerSocket serverSocket = new ServerSocket();
        final MockSocketConnectionHandler handler = new MockSocketConnectionHandler();
        final AcceptorConfig config =
           new AcceptorConfig( name, serverSocket, handler );
        assertEquals( "name", name, config.getName() );
        assertEquals( "serverSocket", serverSocket, config.getServerSocket() );
        assertEquals( "handler", handler, config.getHandler() );
     }
  
     public void testNullNameInCtor()
        throws Exception
     {
        try
        {
           new AcceptorConfig( null,
                               new ServerSocket(),
                               new MockSocketConnectionHandler() );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "name", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to NPE for name" );
     }
  
     public void testNullServerSocketInCtor()
        throws Exception
     {
        try
        {
           new AcceptorConfig( "name",
                               null,
                               new MockSocketConnectionHandler() );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "serverSocket", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to NPE for serverSocket" );
     }
  
     public void testNullHandlerInCtor()
        throws Exception
     {
        try
        {
           new AcceptorConfig( "name",
                               new ServerSocket(),
                               null );
        }
        catch ( NullPointerException npe )
        {
           assertEquals( "npe.message", "handler", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to NPE for handler" );
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/DNAAcceptorMonitorTestCase.java
  
  Index: DNAAcceptorMonitorTestCase.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.ServerSocket;
  import java.io.IOException;
  
  import com.mockobjects.dynamic.C;
  import com.mockobjects.dynamic.Mock;
  import junit.framework.TestCase;
  import org.jcontainer.dna.Logger;
  
  public class DNAAcceptorMonitorTestCase
     extends TestCase
  {
     public void testDNAAcceptorMonitor()
        throws Exception
     {
        final Mock mockLogger = new Mock( Logger.class );
  
        final String name = "MyName";
        final ServerSocket serverSocket = new ServerSocket( 2023 );
        final IOException ioe = new IOException();
  
        final String acceptorCreatedMessage =
           "Creating Acceptor " + name + " on " +
           serverSocket.getInetAddress().getHostAddress() + ":" +
           serverSocket.getLocalPort() + ".";
  
        final String acceptorClosingMessage =
           "Closing Acceptor " + name + ".";
  
        final String serverSocketListening =
           "About to call accept() on ServerSocket '" + name + "'.";
  
        final String errorAcceptingConnectionMessage =
           "Error Accepting connection on " + name;
  
        final String errorClosingServerSocketMessage =
           "Error Closing Server Socket " + name;
  
        mockLogger.expect( "info", C.args( C.eq( acceptorCreatedMessage ) ) );
        mockLogger.expect( "info", C.args( C.eq( acceptorClosingMessage ) ) );
        mockLogger.expectAndReturn( "isDebugEnabled", C.NO_ARGS, false );
        mockLogger.expectAndReturn( "isDebugEnabled", C.NO_ARGS, true );
        mockLogger.expect( "debug", C.args( C.eq( serverSocketListening ) ) );
        mockLogger.expect( "warn", C.args( C.eq( errorAcceptingConnectionMessage ), C.eq( ioe ) ) );
        mockLogger.expect( "warn", C.args( C.eq( errorClosingServerSocketMessage ), C.eq( ioe ) ) );
        final Logger logger = (Logger) mockLogger.proxy();
  
        final AcceptorMonitor monitor = new DNAAcceptorMonitor( logger );
        monitor.acceptorCreated( name, serverSocket );
        monitor.acceptorClosing( name, serverSocket );
        monitor.serverSocketListening( name, serverSocket );
        monitor.serverSocketListening( name, serverSocket );
        monitor.errorAcceptingConnection( name, ioe );
        monitor.errorClosingServerSocket( name, ioe );
  
        mockLogger.verify();
     }
  
     public void testDNAAcceptorMonitorPassedNullIntoCtor()
        throws Exception
     {
        try
        {
           new DNAAcceptorMonitor( null );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.getMessage()", "logger", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to npe in ctor" );
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/DNAAcceptorManagerTestCase.java
  
  Index: DNAAcceptorManagerTestCase.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import junit.framework.TestCase;
  import org.jcontainer.dna.impl.DefaultConfiguration;
  import org.jcontainer.dna.impl.ConsoleLogger;
  
  public class DNAAcceptorManagerTestCase
     extends TestCase
  {
     public void testDNAAcceptorManager()
        throws Exception
     {
        final DNAAcceptorManager manager = new DNAAcceptorManager();
        final DefaultConfiguration root = new DefaultConfiguration( "root", "", "" );
        final DefaultConfiguration configuration = new DefaultConfiguration( "shutdownTimeout", "", "" );
        configuration.setValue( "22" );
        root.addChild( configuration );
  
        final ConsoleLogger logger = new ConsoleLogger( ConsoleLogger.LEVEL_NONE );
        manager.enableLogging( logger );
        final AcceptorMonitor monitor = manager.getMonitor();
        assertTrue( "getMonitor() instanceof DNAAcceptorMonitor", monitor instanceof DNAAcceptorMonitor );
        final DNAAcceptorMonitor dnaMonitor = (DNAAcceptorMonitor) monitor;
        assertEquals( "logger", logger, dnaMonitor.getLogger() );
        manager.configure( root );
        assertEquals( "getShutdownTimeout()", 22, manager.getShutdownTimeout() );
        manager.initialize();
        manager.dispose();
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/PicoAcceptorManagerTestCase.java
  
  Index: PicoAcceptorManagerTestCase.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.impl;
  
  import junit.framework.TestCase;
  
  public class PicoAcceptorManagerTestCase
     extends TestCase
  {
     public void testPicoAcceptorManagerWithMonitorAndShutdownSet()
        throws Exception
     {
        final NullAcceptorMonitor monitor = new NullAcceptorMonitor();
        final PicoAcceptorManager manager = new PicoAcceptorManager( 22, monitor );
        assertEquals( "shutdownTimeout", 22, manager.getShutdownTimeout() );
        assertEquals( "monitor", monitor, manager.getMonitor() );
     }
  
     public void testPicoAcceptorManagerWithShutdownSet()
        throws Exception
     {
        final PicoAcceptorManager manager = new PicoAcceptorManager( 22 );
        assertEquals( "shutdownTimeout", 22, manager.getShutdownTimeout() );
        assertEquals( "monitor", NullAcceptorMonitor.MONITOR, manager.getMonitor() );
     }
  
     public void testPicoAcceptorManagerWithMonitorSet()
        throws Exception
     {
        final NullAcceptorMonitor monitor = new NullAcceptorMonitor();
        final PicoAcceptorManager manager = new PicoAcceptorManager( monitor );
        assertEquals( "shutdownTimeout", 0, manager.getShutdownTimeout() );
        assertEquals( "monitor", monitor, manager.getMonitor() );
     }
  
     public void testPicoAcceptorManagerWithDefaultCtor()
        throws Exception
     {
        final PicoAcceptorManager manager = new PicoAcceptorManager();
        assertEquals( "shutdownTimeout", 0, manager.getShutdownTimeout() );
        assertEquals( "monitor", NullAcceptorMonitor.MONITOR, manager.getMonitor() );
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/ClosingSocketConnectionHandler.java
  
  Index: ClosingSocketConnectionHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.OutputStream;
  import java.net.Socket;
  
  import org.codehaus.spice.netserve.connection.handlers.AbstractRequestHandler;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ClosingSocketConnectionHandler
     extends AbstractRequestHandler
  {
     static final String MESSAGE = "Bye!";
  
     protected void doPerformRequest( Socket socket )
        throws Exception
     {
        final OutputStream outputStream = socket.getOutputStream();
        outputStream.write( MESSAGE.getBytes() );
        outputStream.flush();
        outputStream.close();
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/RecordingAcceptorMonitor.java
  
  Index: RecordingAcceptorMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class RecordingAcceptorMonitor
     extends NullAcceptorMonitor
  {
     private IOException m_errorClosingServerSocket;
     private IOException m_errorAcceptingConnection;
     private int m_listenCount;
  
     public void serverSocketListening( String name, ServerSocket serverSocket )
     {
        m_listenCount++;
        super.serverSocketListening( name, serverSocket );
     }
  
     public void errorAcceptingConnection( String name, IOException ioe )
     {
        m_errorAcceptingConnection = ioe;
        super.errorAcceptingConnection( name, ioe );
     }
  
     public void errorClosingServerSocket( String name, IOException ioe )
     {
        m_errorClosingServerSocket = ioe;
        super.errorClosingServerSocket( name, ioe );
     }
  
     IOException getErrorClosingServerSocket()
     {
        return m_errorClosingServerSocket;
     }
  
     IOException getErrorAcceptingConnection()
     {
        return m_errorAcceptingConnection;
     }
  
     int getListenCount()
     {
        return m_listenCount;
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/MockSocketConnectionHandler.java
  
  Index: MockSocketConnectionHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.Socket;
  
  import org.codehaus.spice.netserve.connection.handlers.AbstractRequestHandler;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class MockSocketConnectionHandler
     extends AbstractRequestHandler
  {
     private Socket m_socket;
  
     protected void doPerformRequest( Socket socket )
        throws Exception
     {
        m_socket = socket;
     }
  
     Socket getSocket()
     {
        return m_socket;
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/ExceptOnCloseServerSocket.java
  
  Index: ExceptOnCloseServerSocket.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ExceptOnCloseServerSocket
     extends ServerSocket
  {
     static final IOException EXCEPTION = new IOException( "No Close - ha ha!" );
  
     public ExceptOnCloseServerSocket()
        throws IOException
     {
     }
  
     public void close() throws IOException
     {
        throw EXCEPTION;
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/ExceptOnAcceptServerSocket.java
  
  Index: ExceptOnAcceptServerSocket.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.io.InterruptedIOException;
  import java.net.ServerSocket;
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ExceptOnAcceptServerSocket
     extends ServerSocket
  {
     static final IOException ERROR_EXCEPTION = new IOException( "No Accept - ha ha!" );
     static final IOException INTERRUPTED_EXCEPTION = new InterruptedIOException( "No Interuptions!" );
  
     private boolean m_interupt;
  
     public ExceptOnAcceptServerSocket( final boolean interupt )
        throws IOException
     {
        m_interupt = interupt;
     }
  
     public Socket accept() throws IOException
     {
        if ( m_interupt )
        {
           throw INTERRUPTED_EXCEPTION;
        }
        else
        {
           throw ERROR_EXCEPTION;
        }
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/ConnectionAcceptorTestCase.java
  
  Index: ConnectionAcceptorTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.ServerSocket;
  
  import junit.framework.TestCase;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class ConnectionAcceptorTestCase
     extends TestCase
  {
     public void testNullConfigInCtor()
        throws Exception
     {
        try
        {
           new ConnectionAcceptor( null,
                                   new NullAcceptorMonitor() );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "config", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to NPE for config" );
     }
  
     public void testNullMonitorInCtor()
        throws Exception
     {
        try
        {
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       new ServerSocket(),
                                                       new MockSocketConnectionHandler() ),
                                   null );
        }
        catch ( NullPointerException npe )
        {
           assertEquals( "npe.message", "monitor", npe.getMessage() );
           return;
        }
        fail( "Expected to fail due to NPE for monitor" );
     }
  
     public void testShutdownServerSocketCausesError()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       new ExceptOnCloseServerSocket(),
                                                       new MockSocketConnectionHandler() ),
                                   monitor );
        assertEquals( "errorClosingServerSocket pre-shutdownServerSocket()",
                      null,
                      monitor.getErrorClosingServerSocket() );
        acceptor.shutdownServerSocket();
        assertEquals( "errorClosingServerSocket post-shutdownServerSocket()",
                      ExceptOnCloseServerSocket.EXCEPTION,
                      monitor.getErrorClosingServerSocket() );
     }
  
     public void testShutdownServerSocket()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       new ServerSocket(),
                                                       new MockSocketConnectionHandler() ),
                                   monitor );
        assertEquals( "errorClosingServerSocket pre-shutdownServerSocket()",
                      null,
                      monitor.getErrorClosingServerSocket() );
        acceptor.shutdownServerSocket();
        assertEquals( "errorClosingServerSocket post-shutdownServerSocket()",
                      null,
                      monitor.getErrorClosingServerSocket() );
     }
  
     public void testExceptionOnAccept()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       new ExceptOnAcceptServerSocket( false ),
                                                       new MockSocketConnectionHandler() ),
                                   monitor );
        assertEquals( "getErrorAcceptingConnection pre-shutdownServerSocket()",
                      null,
                      monitor.getErrorAcceptingConnection() );
        final Thread thread = startAcceptor( acceptor );
        waitUntilStarted( acceptor );
        waitUntilListening( monitor );
  
        assertEquals( "getErrorAcceptingConnection post-shutdownServerSocket()",
                      ExceptOnAcceptServerSocket.ERROR_EXCEPTION,
                      monitor.getErrorAcceptingConnection() );
  
        acceptor.close( 0 );
        thread.join();
     }
  
     public void testInteruptOnAccept()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       new ExceptOnAcceptServerSocket( true ),
                                                       new MockSocketConnectionHandler() ),
                                   monitor );
        final Thread thread = startAcceptor( acceptor );
        waitUntilStarted( acceptor );
        waitUntilListening( monitor );
  
        try
        {
           Thread.sleep( 30 );
        }
        catch ( final InterruptedException e )
        {
        }
        assertTrue( "1 < monitor.getListenCount", 1 < monitor.getListenCount() );
  
        acceptor.close( 0 );
        thread.join();
     }
  
     public void _testNormalHandlerAccept()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final BlockingServerSocket serverSocket = new BlockingServerSocket();
        final MockSocketConnectionHandler handler = new MockSocketConnectionHandler();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       serverSocket,
                                                       handler ),
                                   monitor );
        final Thread thread = startAcceptor( acceptor );
        waitUntilStarted( acceptor );
        waitUntilListening( monitor );
        serverSocket.unlock();
        try
        {
           Thread.sleep( 30 );
        }
        catch ( final InterruptedException e )
        {
        }
        assertEquals( "handler.getSocket()",
                      BlockingServerSocket.SOCKET,
                      handler.getSocket() );
        acceptor.close( 50 );
        serverSocket.unlock();
        thread.join();
     }
  
     public void testAcceptAfterClose()
        throws Exception
     {
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        final BlockingServerSocket serverSocket = new BlockingServerSocket();
        final MockSocketConnectionHandler handler = new MockSocketConnectionHandler();
        final ConnectionAcceptor acceptor =
           new ConnectionAcceptor( new AcceptorConfig( "name",
                                                       serverSocket,
                                                       handler ),
                                   monitor );
        final Thread thread = startAcceptor( acceptor );
        waitUntilStarted( acceptor );
        waitUntilListening( monitor );
        acceptor.close( 50 );
        serverSocket.unlock();
        waitUntilListening( monitor );
        assertEquals( "handler.getSocket()",
                      null,
                      handler.getSocket() );
        serverSocket.unlock();
        thread.join();
     }
  
     private void waitUntilListening( final RecordingAcceptorMonitor monitor )
     {
        while ( 0 == monitor.getListenCount() )
        {
           try
           {
              Thread.sleep( 30 );
           }
           catch ( final InterruptedException e )
           {
           }
        }
     }
  
     private Thread startAcceptor( final ConnectionAcceptor acceptor )
     {
        final Thread thread = new Thread( acceptor );
        thread.start();
        return thread;
     }
  
     private void waitUntilStarted( final ConnectionAcceptor acceptor )
     {
        while ( !acceptor.isRunning() )
        {
           try
           {
              Thread.sleep( 30 );
           }
           catch ( final InterruptedException e )
           {
           }
        }
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/BlockingServerSocket.java
  
  Index: BlockingServerSocket.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.io.IOException;
  import java.net.ServerSocket;
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class BlockingServerSocket
     extends ServerSocket
  {
     static final Socket SOCKET = new Socket();
  
     private int m_lockCount;
     private int m_acceptCount;
  
     public BlockingServerSocket()
        throws IOException
     {
     }
  
     public Socket accept()
        throws IOException
     {
        m_acceptCount++;
        while ( true )
        {
           synchronized ( this )
           {
              if ( m_acceptCount <= m_lockCount )
              {
                 break;
              }
              try
              {
                 wait( 100 );
              }
              catch ( InterruptedException e )
              {
              }
              notifyAll();
           }
        }
        return SOCKET;
     }
  
     synchronized void unlock()
     {
        m_lockCount++;
        notifyAll();
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/impl/DefaultAcceptorManagerTestCase.java
  
  Index: DefaultAcceptorManagerTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.impl;
  
  import java.net.Socket;
  import java.net.InetAddress;
  import java.net.InetSocketAddress;
  import java.net.ServerSocket;
  import java.nio.channels.ServerSocketChannel;
  import java.util.Random;
  
  import junit.framework.TestCase;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class DefaultAcceptorManagerTestCase
     extends TestCase
  {
     public void testConnectAndDisconnectWithTimeoutNotSet()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        manager.setMonitor( NullAcceptorMonitor.MONITOR );
        manager.setSoTimeout( 10 );
        manager.setShutdownTimeout( 0 );
        final String name = "name";
        assertEquals( "isConnected pre connect", false, manager.isConnected( name ) );
        final ExceptOnAcceptServerSocket socket = new ExceptOnAcceptServerSocket( true );
        assertEquals( "socket.getSoTimeout pre connect", 0, socket.getSoTimeout() );
        manager.connect( name,
                         socket,
                         new MockSocketConnectionHandler() );
        assertEquals( "socket.getSoTimeout post connect", 10, socket.getSoTimeout() );
        assertEquals( "isConnected pre disconnect", true, manager.isConnected( name ) );
        manager.disconnect( name );
        assertEquals( "isConnected post disconnect", false, manager.isConnected( name ) );
     }
  
     public void testShutdownAcceptors()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        manager.setMonitor( NullAcceptorMonitor.MONITOR );
        manager.setSoTimeout( 10 );
        final String name = "name";
        assertEquals( "isConnected pre connect", false, manager.isConnected( name ) );
        manager.connect( name,
                         new ExceptOnAcceptServerSocket( true ),
                         new MockSocketConnectionHandler() );
        assertEquals( "isConnected pre shutdownAcceptors", true, manager.isConnected( name ) );
        manager.shutdownAcceptors();
        assertEquals( "isConnected post shutdownAcceptors", false, manager.isConnected( name ) );
     }
  
     public void testConnectAndDisconnectWithTimeoutSet()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        manager.setMonitor( NullAcceptorMonitor.MONITOR );
        manager.setSoTimeout( 10 );
        final String name = "name";
        assertEquals( "isConnected pre connect", false, manager.isConnected( name ) );
        final ExceptOnAcceptServerSocket socket = new ExceptOnAcceptServerSocket( true );
        socket.setSoTimeout( 123 );
        assertEquals( "socket.getSoTimeout pre connect", 123, socket.getSoTimeout() );
        manager.connect( name,
                         socket,
                         new MockSocketConnectionHandler() );
        assertEquals( "socket.getSoTimeout post connect", 123, socket.getSoTimeout() );
        assertEquals( "isConnected pre disconnect", true, manager.isConnected( name ) );
        manager.disconnect( name );
        assertEquals( "isConnected post disconnect", false, manager.isConnected( name ) );
     }
  
     public void testConnectAndAcceptAndDisconnectWithTimeoutSet()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        final RecordingAcceptorMonitor monitor = new RecordingAcceptorMonitor();
        manager.setMonitor( monitor );
        manager.setSoTimeout( 10 );
        final String name = "name";
        assertEquals( "isConnected pre connect", false, manager.isConnected( name ) );
        final ServerSocketChannel channel = ServerSocketChannel.open();
        final ServerSocket serverSocket = channel.socket();
        serverSocket.setReuseAddress( true );
        final InetAddress localAddress = InetAddress.getLocalHost();
        final Random random = new Random();
        final int port = Math.abs( random.nextInt() % 5000 ) + 1024;
        final InetSocketAddress address = new InetSocketAddress( localAddress, port );
        serverSocket.bind( address );
        while ( !serverSocket.isBound() )
        {
           System.out.print( "." );
           Thread.yield();
        }
  
        final MockSocketConnectionHandler handler = new MockSocketConnectionHandler();
        manager.connect( name, serverSocket, handler );
  
        final Socket clientSocket = new Socket( localAddress, port );
        System.out.print( "Socket Connecting" );
        while ( !clientSocket.isConnected() )
        {
           System.out.print( "." );
           Thread.yield();
        }
        System.out.println( " - Connected" );
        clientSocket.close();
  
        //Sleep to make sure accept goes through
        Thread.sleep( 200 );
  
        assertNotNull( "handler.socket", handler.getSocket() );
  
        assertEquals( "isConnected pre disconnect", true, manager.isConnected( name ) );
        manager.disconnect( name );
        assertEquals( "isConnected post disconnect", false, manager.isConnected( name ) );
     }
  
     public void testDuplicateConnect()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        final String name = "name";
        assertEquals( "isConnected pre connect", false, manager.isConnected( name ) );
        final ExceptOnAcceptServerSocket socket = new ExceptOnAcceptServerSocket( true );
        manager.connect( name,
                         socket,
                         new MockSocketConnectionHandler() );
        assertEquals( "isConnected pre disconnect", true, manager.isConnected( name ) );
        try
        {
           manager.connect( name,
                            new ExceptOnAcceptServerSocket( true ),
                            new MockSocketConnectionHandler() );
        }
        catch ( final IllegalArgumentException iae )
        {
           return;
        }
        finally
        {
           socket.close();
           manager.shutdownAcceptors();
           assertEquals( "isConnected post disconnect", false, manager.isConnected( name ) );
        }
        fail( "Expected to fail due to duplicate connect" );
     }
  
     public void testDisconnectNonExistent()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        try
        {
           manager.disconnect( "NonExistent" );
        }
        catch ( IllegalArgumentException iae )
        {
           return;
        }
        finally
        {
           manager.shutdownAcceptors();
        }
        fail( "Expected to fail to disconnect non existent acceptor" );
     }
  
     public void testConnectWithNullName()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        try
        {
           manager.connect( null,
                            new ExceptOnAcceptServerSocket( true ),
                            new MockSocketConnectionHandler() );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "name", npe.getMessage() );
           return;
        }
        finally
        {
           manager.shutdownAcceptors();
        }
        fail( "expected NPE due to null name in connect" );
     }
  
     public void testConnectWithNullSocket()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        try
        {
           manager.connect( "name",
                            null,
                            new MockSocketConnectionHandler() );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "socket", npe.getMessage() );
           return;
        }
        finally
        {
           manager.shutdownAcceptors();
        }
        fail( "expected NPE due to null socket in connect" );
     }
  
     public void testConnectWithNullHandler()
        throws Exception
     {
        final DefaultAcceptorManager manager = new DefaultAcceptorManager();
        try
        {
           manager.connect( "name",
                            new ExceptOnAcceptServerSocket( true ),
                            null );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.message", "handler", npe.getMessage() );
           return;
        }
        finally
        {
           manager.shutdownAcceptors();
        }
        fail( "expected NPE due to null handler in connect" );
     }
  
      protected void setUp() throws Exception
      {
          System.out.print( "Test: " + getName() );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/RequestHandlerTestCase.java
  
  Index: RequestHandlerTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import junit.framework.TestCase;
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class RequestHandlerTestCase
      extends TestCase
  {
      public void testEndConnectionWithError()
          throws Exception
      {
          final MockRequestHandler handler = new MockRequestHandler();
          final ExceptionOnCloseSocket socket = new ExceptionOnCloseSocket();
          handler.endConnection( socket );
          assertEquals( "getErrorClosingConnectionSocket",
                        socket,
                        handler.getErrorClosingConnectionSocket() );
          assertEquals( "getErrorClosingConnectionThrowable",
                        ExceptionOnCloseSocket.IO_EXCEPTION,
                        handler.getErrorClosingConnectionThrowable() );
      }
  
      public void testCreateRunnable()
          throws Exception
      {
          final MockRequestHandler handler = new MockRequestHandler();
          final Socket socket = new Socket();
          final Runnable runnable = handler.createRunnable( socket );
          runnable.run();
          assertEquals( "getPerformRequestSocket",
                        socket,
                        handler.getPerformRequestSocket() );
      }
  
      public void testPerformRequestWithError()
          throws Exception
      {
          final ExceptingRequestHandler handler = new ExceptingRequestHandler();
          final Socket socket = new Socket();
          handler.performRequest( socket );
          assertEquals( "getPerformRequestSocket",
                        socket,
                        handler.getPerformRequestSocket() );
          assertEquals( "getErrorHandlingConnectionSocket",
                        socket,
                        handler.getErrorHandlingConnectionSocket() );
          assertEquals( "getErrorClosingConnectionThrowable",
                        ExceptingRequestHandler.EXCEPTION,
                        handler.getErrorHandlingConnectionThrowable() );
      }
  
      public void testShutdownWhileThreadStillGoingButInteruptible()
          throws Exception
      {
          final DelayingRequestHandler handler = new DelayingRequestHandler( 2000, true );
          final Socket socket = new Socket();
          final Runnable runnable = new Runnable()
          {
              public void run()
              {
                  handler.handleConnection( socket );
              }
          };
          final Thread thread = new Thread( runnable );
          thread.start();
          Thread.sleep( 50 );
  
          handler.shutdown( 50 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", true, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", true, handler.isExitDueToInterrupt() );
      }
  
      public void testShutdownWhileThreadStillGoingAndNotInteruptible()
          throws Exception
      {
          final DelayingRequestHandler handler =
              new DelayingRequestHandler( 2000, false );
          final Socket socket = new Socket();
          final Runnable runnable = new Runnable()
          {
              public void run()
              {
                  handler.handleConnection( socket );
              }
          };
          final Thread thread = new Thread( runnable );
          thread.start();
          Thread.sleep( 50 );
  
          handler.shutdown( 50 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", false, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", false, handler.isExitDueToInterrupt() );
      }
  
      public void testShutdownWhileThreadStillGoingAndWaitIndefinetly()
          throws Exception
      {
          final DelayingRequestHandler handler =
              new DelayingRequestHandler( 200, false );
          final Socket socket = new Socket();
          final Runnable runnable = new Runnable()
          {
              public void run()
              {
                  handler.handleConnection( socket );
              }
          };
          final Thread thread = new Thread( runnable );
          thread.start();
          Thread.sleep( 50 );
  
          handler.shutdown( 0 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", true, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", false, handler.isExitDueToInterrupt() );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/MockRequestHandler.java
  
  Index: MockRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class MockRequestHandler
      extends AbstractRequestHandler
  {
      private Socket m_performRequestSocket;
  
      private Socket m_errorClosingConnectionSocket;
      private Throwable m_errorClosingConnectionThrowable;
  
      private Socket m_errorHandlingConnectionSocket;
      private Throwable m_errorHandlingConnectionThrowable;
  
      protected void doPerformRequest( Socket socket )
          throws Exception
      {
          m_performRequestSocket = socket;
      }
  
      protected void errorClosingConnection( Socket socket,
                                             Throwable t )
      {
          super.errorClosingConnection( socket, t );
          m_errorClosingConnectionSocket = socket;
          m_errorClosingConnectionThrowable = t;
      }
  
      protected void errorHandlingConnection( Socket socket,
                                              Throwable t )
      {
          super.errorHandlingConnection( socket, t );
          m_errorHandlingConnectionSocket = socket;
          m_errorHandlingConnectionThrowable = t;
      }
  
      Socket getPerformRequestSocket()
      {
          return m_performRequestSocket;
      }
  
      Socket getErrorClosingConnectionSocket()
      {
          return m_errorClosingConnectionSocket;
      }
  
      Throwable getErrorClosingConnectionThrowable()
      {
          return m_errorClosingConnectionThrowable;
      }
  
      Socket getErrorHandlingConnectionSocket()
      {
          return m_errorHandlingConnectionSocket;
      }
  
      Throwable getErrorHandlingConnectionThrowable()
      {
          return m_errorHandlingConnectionThrowable;
      }
  }
  
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/ExceptingRequestHandler.java
  
  Index: ExceptingRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ExceptingRequestHandler
      extends MockRequestHandler
  {
      static final Exception EXCEPTION = new Exception();
  
      protected void doPerformRequest( Socket socket )
          throws Exception
      {
          super.doPerformRequest(socket );
          throw EXCEPTION;
      }
  }
  
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/DelegatingRequestHandlerTestCase.java
  
  Index: DelegatingRequestHandlerTestCase.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  
  import com.mockobjects.dynamic.C;
  import com.mockobjects.dynamic.Mock;
  import junit.framework.TestCase;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  public class DelegatingRequestHandlerTestCase
     extends TestCase
  {
     public void testNullPassedIntoCtor()
        throws Exception
     {
        try
        {
           new DelegatingRequestHandler( null );
        }
        catch ( final NullPointerException npe )
        {
           assertEquals( "npe.getMessage()", "handler", npe.getMessage() );
           return;
        }
     }
  
     public void testDelegateHandlerInvoked()
        throws Exception
     {
        final Mock mockHandler = new Mock( RequestHandler.class );
        final Socket socket = new Socket();
        final Long timeout = new Long( 23 );
        mockHandler.expect( "handleConnection", C.args( C.eq( socket ) ) );
        mockHandler.expect( "shutdown", C.args( C.eq( timeout ) ) );
        final RequestHandler handler = (RequestHandler) mockHandler.proxy();
        final DelegatingRequestHandler delegatingHandler =
           new DelegatingRequestHandler( handler );
  
        delegatingHandler.handleConnection( socket );
        delegatingHandler.shutdown( 23 );
     }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/ManagedRequestHandlerTestCase.java
  
  Index: ManagedRequestHandlerTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import com.mockobjects.dynamic.C;
  import com.mockobjects.dynamic.Mock;
  import java.net.Socket;
  import junit.framework.TestCase;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class ManagedRequestHandlerTestCase
      extends TestCase
  {
      public void testManagedRequestHandler()
          throws Exception
      {
          final Mock mockHandler = new Mock( RequestHandler.class );
          final Socket socket = new Socket();
          mockHandler.expect( "handleConnection", C.args( C.eq( socket ) ) );
          final RequestHandler handler = (RequestHandler)mockHandler.proxy();
  
          final Mock mockManager = new Mock( RequestManager.class );
          mockManager.expectAndReturn( "aquireHandler",
                                       C.args( C.isA( Socket.class ) ),
                                       handler );
          mockManager.expect( "releaseHandler",
                              C.args( C.eq( handler ) ) );
  
          final RequestManager manager = (RequestManager)mockManager.proxy();
  
          final MockManagedRequestHandler managedHandler =
              new MockManagedRequestHandler( manager );
          managedHandler.handleConnection( socket );
  
          mockManager.verify();
          mockHandler.verify();
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/MockThreadPool.java
  
  Index: MockThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.codehaus.spice.threadpool.ThreadControl;
  import org.codehaus.spice.threadpool.Executable;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class MockThreadPool
      implements ThreadPool
  {
      public ThreadControl execute( Runnable work )
      {
          final Thread thread = new Thread( work );
          thread.start();
          return new MockThreadControl( thread );
      }
  
      public ThreadControl execute( Executable work )
      {
          return null;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/ThreadPerRequestHandlerTestCase.java
  
  Index: ThreadPerRequestHandlerTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import junit.framework.TestCase;
  import com.mockobjects.dynamic.Mock;
  import com.mockobjects.dynamic.C;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.codehaus.spice.threadpool.ThreadControl;
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public class ThreadPerRequestHandlerTestCase
      extends TestCase
  {
      public void testNullThreadPoolPassedToCtor()
          throws Exception
      {
          final Mock mockHandler = new Mock( RequestHandler.class );
          final RequestHandler handler = (RequestHandler)mockHandler.proxy();
          try
          {
              new ThreadPerRequestHandler( handler, null );
          }
          catch( final NullPointerException npe )
          {
              assertEquals( "npe.getMessage()", "threadPool", npe.getMessage() );
              return;
          }
          fail( "Expected to fail due to null ThreadPool passed into Ctor" );
      }
  
      public void testThreadPoolInvoked()
          throws Exception
      {
          final Mock mockControl = new Mock( ThreadControl.class );
          final ThreadControl control = (ThreadControl)mockControl.proxy();
  
          final Mock mockHandler = new Mock( RequestHandler.class );
          final RequestHandler handler = (RequestHandler)mockHandler.proxy();
  
          final Mock mockPool = new Mock( ThreadPool.class );
          mockPool.expectAndReturn( "execute", C.args( C.isA( Runnable.class ) ), control );
          final ThreadPool threadPool = (ThreadPool)mockPool.proxy();
  
          final ThreadPerRequestHandler requestHandler =
              new ThreadPerRequestHandler( handler, threadPool );
          requestHandler.handleConnection( new Socket() );
  
          mockHandler.verify();
          mockPool.verify();
          mockControl.verify();
      }
  
      public void testShutdownWhileThreadStillGoingButInteruptible()
          throws Exception
      {
          final DelayingRequestHandler handler =
              new DelayingRequestHandler( 2000, true );
  
          final ThreadPerRequestHandler requestHandler =
              new ThreadPerRequestHandler( handler, new MockThreadPool() );
          requestHandler.handleConnection( new Socket() );
          Thread.sleep( 50 );
  
          requestHandler.shutdown( 50 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", true, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", true, handler.isExitDueToInterrupt() );
      }
  
      public void testShutdownWhileThreadStillGoingAndNotInteruptible()
          throws Exception
      {
          final DelayingRequestHandler handler =
              new DelayingRequestHandler( 2000, false );
  
          final ThreadPerRequestHandler requestHandler =
              new ThreadPerRequestHandler( handler, new MockThreadPool() );
          requestHandler.handleConnection( new Socket() );
          Thread.sleep( 50 );
  
          requestHandler.shutdown( 50 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", false, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", false, handler.isExitDueToInterrupt() );
      }
  
      public void testShutdownWhileThreadStillGoingAndWaitIndefinetly()
          throws Exception
      {
          final DelayingRequestHandler handler =
              new DelayingRequestHandler( 200, false );
  
          final ThreadPerRequestHandler requestHandler =
              new ThreadPerRequestHandler( handler, new MockThreadPool() );
          requestHandler.handleConnection( new Socket() );
          Thread.sleep( 50 );
  
          requestHandler.shutdown( 0 );
          assertEquals( "isShutdown", true, handler.isShutdown() );
          assertEquals( "isExited", true, handler.isExited() );
          assertEquals( "isExitDueToInterrupt", false, handler.isExitDueToInterrupt() );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/ExceptionOnCloseSocket.java
  
  Index: ExceptionOnCloseSocket.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  import java.io.IOException;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class ExceptionOnCloseSocket
      extends Socket
  {
      static final IOException IO_EXCEPTION = new IOException();
  
      public boolean isConnected()
      {
          return true;
      }
  
      public synchronized void close() throws IOException
      {
          throw IO_EXCEPTION;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/DelayingRequestHandler.java
  
  Index: DelayingRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class DelayingRequestHandler
      extends AbstractRequestHandler
  {
      private final long m_delay;
      private final boolean m_wakeupOnInterrupt;
  
      private boolean m_exited;
      private boolean m_exitDueToInterrupt;
  
      DelayingRequestHandler( final long delay,
                              final boolean wakeupOnInterrupt )
      {
          m_delay = delay;
          m_wakeupOnInterrupt = wakeupOnInterrupt;
      }
  
      protected void doPerformRequest( Socket socket )
          throws Exception
      {
          final int code = System.identityHashCode( this );
          final String prefix = "Handler(" + code + ") ";
          System.out.println( prefix + "Started" );
          final long then = System.currentTimeMillis() + m_delay;
          while( System.currentTimeMillis() < then )
          {
              final long rest = then - System.currentTimeMillis();
              System.out.println( prefix + "Sleeping for " + rest );
              try
              {
                  Thread.sleep( rest );
              }
              catch( InterruptedException e )
              {
                  System.out.println( prefix + "Woken up" );
                  if( m_wakeupOnInterrupt )
                  {
                      m_exitDueToInterrupt = true;
                      break;
                  }
              }
          }
          m_exited = true;
          System.out.println( prefix + "Returning" );
      }
  
      boolean isExitDueToInterrupt()
      {
          return m_exitDueToInterrupt;
      }
  
      boolean isExited()
      {
          return m_exited;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/MockManagedRequestHandler.java
  
  Index: MockManagedRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class MockManagedRequestHandler
      extends ManagedRequestHandler
  {
      private final RequestManager m_requestManager;
  
      public MockManagedRequestHandler( RequestManager requestManager )
      {
          m_requestManager = requestManager;
      }
  
      protected RequestHandler aquireHandler( Socket socket )
      {
          return m_requestManager.aquireHandler( socket );
      }
  
      protected void releaseHandler( RequestHandler handler )
      {
          m_requestManager.releaseHandler( handler );
      }
  }
  
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/MockThreadControl.java
  
  Index: MockThreadControl.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import org.codehaus.spice.threadpool.ThreadControl;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  class MockThreadControl
      implements ThreadControl
  {
      private final Thread m_thread;
  
      public MockThreadControl( Thread thread )
      {
          m_thread = thread;
      }
  
      public void join( long milliSeconds )
          throws InterruptedException
      {
          m_thread.join( milliSeconds );
      }
  
      public void interrupt()
          throws IllegalStateException, SecurityException
      {
          m_thread.interrupt();
      }
  
      public boolean isFinished()
      {
          return !m_thread.isAlive();
      }
  
      public Throwable getThrowable()
      {
          return null;
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/connection/handlers/RequestManager.java
  
  Index: RequestManager.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import org.codehaus.spice.netserve.connection.RequestHandler;
  import java.net.Socket;
  
  /**
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:05 $
   */
  public interface RequestManager
  {
      RequestHandler aquireHandler( Socket socket );
  
      void releaseHandler( RequestHandler handler );
  }
  
  
  
  1.13      +5 -5      spice/components/netserve/project.xml
  
  Index: project.xml
  ===================================================================
  RCS file: /scm/cvs/spice/components/netserve/project.xml,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- project.xml	19 Nov 2003 17:38:34 -0000	1.12
  +++ project.xml	20 Nov 2003 00:25:06 -0000	1.13
  @@ -4,8 +4,8 @@
       <name>Netserve</name>
       <id>spice-netserve</id>
       <gumpRepositoryId>components</gumpRepositoryId>
  -    <package>org.jcomponent.netserve</package>
  -    <currentVersion>0.7</currentVersion>
  +    <package>org.codehaus.spice.netserve</package>
  +    <currentVersion>1.0-b1</currentVersion>
       <inceptionYear>1999</inceptionYear>
   
       <shortDescription>Components useful for creating a Network Server.</shortDescription>
  @@ -38,9 +38,9 @@
               <version>1.0</version>
           </dependency>
           <dependency>
  -            <groupId>jcomponent</groupId>
  -           	<artifactId>jcomponent-threadpool</artifactId>
  -            <version>1.0</version>
  +            <groupId>spice</groupId>
  +           	<artifactId>spice-threadpool</artifactId>
  +            <version>1.0-b1</version>
               <properties>
                   <category>runtime</category>
               </properties>
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/handlers/ThreadPerRequestHandler.java
  
  Index: ThreadPerRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  import java.util.Map;
  import java.util.Hashtable;
  import java.util.Collection;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.codehaus.spice.threadpool.ThreadControl;
  
  /**
   * A Handler that uses a thread from a pool for each different request.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public class ThreadPerRequestHandler
      extends DelegatingRequestHandler
  {
      /**
       * A map of Socket->ThreadControl.
       */
      private final Map m_controlMap = new Hashtable();
  
      /**
       * the thread pool that used to handle requests.
       */
      private final ThreadPool m_threadPool;
  
      /**
       * Create handler.
       *
       * @param handler the underlying handler
       * @param threadPool the thread pool to use to create handler threads
       */
      public ThreadPerRequestHandler( final RequestHandler handler,
                                      final ThreadPool threadPool )
      {
          super( handler );
          if( null == threadPool )
          {
              throw new NullPointerException( "threadPool" );
          }
          m_threadPool = threadPool;
      }
  
      /**
       * Execute each request in a separate thread.
       *
       * @param socket the socket to handle
       */
      public void handleConnection( final Socket socket )
      {
          final Runnable runnable = createRunnable( socket );
          final ThreadControl control = m_threadPool.execute( runnable );
          m_controlMap.put( socket, control );
      }
  
      /**
       * Remove ThreadControl from list of active threads.
       *
       * @param socket the socket
       */
      protected void endConnection( Socket socket )
      {
          m_controlMap.remove( socket );
          super.endConnection( socket );
      }
  
      /**
       * Shutdown all requests including those executing in thread pool.
       *
       * @param timeout the timeout
       */
      public void shutdown( final long timeout )
      {
          markAsShutdown();
          final ThreadControl[] controls;
          synchronized( m_controlMap )
          {
              final Collection collection = m_controlMap.values();
              controls = (ThreadControl[])collection.
                  toArray( new ThreadControl[ collection.size() ] );
          }
          for( int i = 0; i < controls.length; i++ )
          {
              final ThreadControl control = controls[ i ];
              if( !control.isFinished() )
              {
                  control.interrupt();
              }
          }
          super.shutdown( timeout );
          for( int i = 0; i < controls.length; i++ )
          {
              final ThreadControl control = controls[ i ];
              if( !control.isFinished() )
              {
                  try
                  {
                      control.join( timeout );
                  }
                  catch( final InterruptedException ie )
                  {
                      //Ignore
                  }
              }
          }
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/handlers/DelegatingRequestHandler.java
  
  Index: DelegatingRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   * A simple handler that delegates to another handler.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public class DelegatingRequestHandler
      extends AbstractRequestHandler
  {
      /**
       * The underlying handler to delegate to.
       */
      private final RequestHandler m_handler;
  
      /**
       * Create handler.
       *
       * @param handler the handler to delegate to
       */
      public DelegatingRequestHandler( final RequestHandler handler )
      {
          if( null == handler )
          {
              throw new NullPointerException( "handler" );
          }
          m_handler = handler;
      }
  
      /**
       * Delegate request to supplied handler.
       *
       * @param socket the socket
       * @throws Exception on error
       */
      protected void doPerformRequest( final Socket socket )
          throws Exception
      {
          m_handler.handleConnection( socket );
      }
  
      /**
       * @see AbstractRequestHandler#shutdown
       */
      public void shutdown( final long timeout )
      {
          m_handler.shutdown( timeout );
          super.shutdown( timeout );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/handlers/AbstractRequestHandler.java
  
  Index: AbstractRequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.io.IOException;
  import java.net.Socket;
  import java.util.HashSet;
  import java.util.Set;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   * Abstract base class for request handlers.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public abstract class AbstractRequestHandler
      implements RequestHandler
  {
      /**
       * The set of active requests.
       */
      private final Set m_activeRequests = new HashSet();
  
      /**
       * True if shutdown() has been called.
       */
      private boolean m_shutdown;
  
      /**
       * Handle a connection.
       *
       * @param socket the socket
       */
      public void handleConnection( Socket socket )
      {
          performRequest( socket );
      }
  
      /**
       * @see RequestHandler#shutdown
       */
      public void shutdown( final long timeout )
      {
          markAsShutdown();
          final Thread[] threads;
          synchronized( this )
          {
              threads = (Thread[])m_activeRequests.
                  toArray( new Thread[ m_activeRequests.size() ] );
          }
          for( int i = 0; i < threads.length; i++ )
          {
              final Thread thread = threads[ i ];
              thread.interrupt();
          }
          final long now = System.currentTimeMillis();
          final long then = now + timeout;
  
          while( System.currentTimeMillis() < then || 0 == timeout )
          {
              synchronized( this )
              {
                  if( 0 == m_activeRequests.size() )
                  {
                      return;
                  }
                  try
                  {
                      wait( timeout );
                  }
                  catch( final InterruptedException ie )
                  {
                      //Ignore
                  }
              }
          }
      }
  
      /**
       * Mark request handler as shutdown.
       */
      protected void markAsShutdown()
      {
          m_shutdown = true;
      }
  
      /**
       * Return true if handler has been shutdown.
       *
       * @return true if handler has been shutdown.
       */
      protected boolean isShutdown()
      {
          return m_shutdown;
      }
  
      /**
       * Perform the request for socket by delegating to
       * underlying handler.
       *
       * @param socket the socket to handle
       */
      protected void performRequest( final Socket socket )
      {
          synchronized( this )
          {
              m_activeRequests.add( Thread.currentThread() );
          }
          setupThreadName( socket );
          try
          {
              doPerformRequest( socket );
          }
          catch( final Throwable t )
          {
              errorHandlingConnection( socket, t );
          }
          finally
          {
              endConnection( socket );
              synchronized( this )
              {
                  m_activeRequests.remove( Thread.currentThread() );
                  notifyAll();
              }
          }
      }
  
      /**
       * Method implemented to actually do the work.
       *
       * @param socket the socket
       * @throws Exception if an error occurs
       */
      protected abstract void doPerformRequest( Socket socket )
          throws Exception;
  
      /**
       * Setup the name of the thread.
       *
       * @param socket the socket associated with request
       */
      protected void setupThreadName( final Socket socket )
      {
          final String name = getThreadName( socket );
          Thread.currentThread().setName( name );
      }
  
      /**
       * End connection for socket.
       *
       * @param socket the socket
       */
      protected void endConnection( final Socket socket )
      {
          if( socket.isConnected() )
          {
              try
              {
                  socket.close();
              }
              catch( final IOException ioe )
              {
                  errorClosingConnection( socket, ioe );
              }
          }
      }
  
      /**
       * Create Runnable to perform the request.
       *
       * @param socket the socket to handle
       * @return thee runnable
       */
      protected Runnable createRunnable( final Socket socket )
      {
          return new Runnable()
          {
              public void run()
              {
                  performRequest( socket );
              }
          };
      }
  
      /**
       * Return the name should be set for current thread.
       *
       * @param socket the socket being handled in thread
       * @return the thread name.
       */
      protected String getThreadName( final Socket socket )
      {
          if( socket.isConnected() )
          {
              return "RequestHandler for " +
                  socket.getInetAddress().getHostAddress() + ":" +
                  socket.getPort();
          }
          else
          {
              return "RequestHandler for " + socket;
          }
      }
  
      /**
       * Notify handler of an error handling socket.
       *
       * @param socket the socket
       * @param t the error
       */
      protected void errorHandlingConnection( final Socket socket,
                                              final Throwable t )
      {
      }
  
      /**
       * Notify handler of an error closing socket.
       *
       * @param socket the socket
       * @param t the error
       */
      protected void errorClosingConnection( final Socket socket,
                                             final Throwable t )
      {
          errorHandlingConnection( socket, t );
      }
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/handlers/ManagedRequestHandler.java
  
  Index: ManagedRequestHandler.java
  ===================================================================
  package org.codehaus.spice.netserve.connection.handlers;
  
  import java.net.Socket;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   * A handler that allows user to handle ConnectionHandlers.
   * Subclasses may pool or create transient handlers etc.
   */
  public abstract class ManagedRequestHandler
      extends AbstractRequestHandler
  {
      /**
       * Actually handle the request.
       * Assume that the caller will gracefully
       * handle unexpected exceptions and shutdown
       * the socket when this method returns.
       *
       * @param socket the socket
       * @throws Exception if an erro roccurs
       */
      protected void doPerformRequest( final Socket socket )
          throws Exception
      {
          final RequestHandler handler = aquireHandler( socket );
          try
          {
              handler.handleConnection( socket );
          }
          finally
          {
              releaseHandler( handler );
          }
      }
  
      /**
       * Retrieve the underlying handler.
       *
       * @param socket the socket
       * @return the RequestHandler
       */
      protected abstract RequestHandler aquireHandler( Socket socket );
  
      /**
       * Release the underlying handler.
       *
       * @param handler the handler
       */
      protected abstract void releaseHandler( RequestHandler handler );
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/RequestHandler.java
  
  Index: RequestHandler.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection;
  
  import java.net.Socket;
  
  /**
   * Implement this interface to process incoming socket connections.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public interface RequestHandler
  {
      /**
       * Processes connections as they occur.
       *
       * @param socket the socket
       */
      void handleConnection( Socket socket );
  
      /**
       * Shutdown the handler and any requests currently being handled.
       * The timeout specifies the time to wait while shutting
       * down request handlers. A timeout of 0 indicates that
       * should wait indefinetly.
       *
       * @param timeout the timeout
       */
      void shutdown( long timeout );
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/connection/SocketAcceptorManager.java
  
  Index: SocketAcceptorManager.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.connection;
  
  import java.net.ServerSocket;
  import org.codehaus.spice.netserve.connection.RequestHandler;
  
  /**
   * This service is used to manage network acceptors.
   * The service takes a ServerSocket and RequestHandler and
   * anytime a new connection is accepted the handler is called
   * with the new socket connection.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public interface SocketAcceptorManager
  {
      /**
       * Start accepting connections from a socket and passing connections
       * to specified handler.
       *
       * @param name the name of connection. This serves as a key used to
       *        shutdown acceptor.
       * @param socket the ServerSocket from which connections are accepted
       * @throws java.lang.Exception if unable to initiate connection management. This could
       *         be due to the key already being used for another acceptor,
       *        the serversocket being closed, the handler being null etc.
       */
      void connect( String name,
                    ServerSocket socket,
                    RequestHandler handler )
          throws Exception;
  
      /**
       * This shuts down the named acceptor.
       * NOTE: It is the responsibility of the caller to make
       * sure that the ServerSocket has been closed.
       *
       * @param name the name of connection
       * @throws java.lang.IllegalArgumentException if no connection with specified name
       */
      void disconnect( String name );
  
      /**
       * Return true if acceptor with specified name exists.
       *
       * @param name the name
       * @return true if acceptor with specified name exists.
       */
      boolean isConnected( String name );
  }
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/ServerSocketFactory.java
  
  Index: ServerSocketFactory.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.sockets;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.ServerSocket;
  
  /**
   * Service used to create server sockets. The factory is used so that
   * the exact socket type and underlying transport is abstracted. The
   * sockets created could be proxied, SSL enabled, TLS enabled etc.
   * However clients just care that they return sockets.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public interface ServerSocketFactory
  {
      /**
       * Creates a socket on specified port.
       *
       * @param port the port (0 indicates any available port)
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      ServerSocket createServerSocket( int port )
          throws IOException;
  
      /**
       * Creates a socket on specified port with a specified backlog.
       *
       * @param port the port (0 indicates any available port)
       * @param backlog the backlog
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      ServerSocket createServerSocket( int port, int backlog )
          throws IOException;
  
      /**
       * Creates a socket on a particular network interface on specified port
       * with a specified backlog.
       *
       * @param port the port (0 indicates any available port)
       * @param backlog the backlog
       * @param address the network interface to bind to.
       * @return the created ServerSocket
       * @throws IOException if unable to create socket
       */
      ServerSocket createServerSocket( int port, int backlog, InetAddress address )
          throws IOException;
  }
  
  
  
  
  1.1                  spice/components/netserve/src/java/org/codehaus/spice/netserve/sockets/SocketFactory.java
  
  Index: SocketFactory.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.sockets;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.Socket;
  
  /**
   * Service used to create client sockets. The factory is used so that
   * the exact socket type and underlying transport is abstracted. The
   * sockets created could be proxied, SSL enabled, TLS enabled etc.
   * However clients just care that they return sockets.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:06 $
   */
  public interface SocketFactory
  {
      /**
       * Create a socket that connects to specified remote address.
       *
       * @param address the remote address
       * @param port the remote port
       * @return the socket connected to remote address
       * @throws IOException if unable to create socket
       */
      Socket createSocket( InetAddress address, int port )
          throws IOException;
  
      /**
       * Create a socket that connects to specified remote address and
       * originates from specified local address.
       *
       * @param address the remote address
       * @param port the remote port
       * @param localAddress the local address
       * @param localPort the local port
       * @return the socket connected to remote address
       * @throws IOException if unable to create socket
       */
      Socket createSocket( InetAddress address, int port,
                           InetAddress localAddress, int localPort )
          throws IOException;
  }
  
  
  
  1.5       +9 -10     spice/components/netserve/xdocs/index.xml
  
  Index: index.xml
  ===================================================================
  RCS file: /scm/cvs/spice/components/netserve/xdocs/index.xml,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- index.xml	5 Nov 2003 08:47:56 -0000	1.4
  +++ index.xml	20 Nov 2003 00:25:07 -0000	1.5
  @@ -13,11 +13,10 @@
               from ACE for both stream based and packet based connections,
               etc.
            </p>
  -            <p>
  +         <p>
               All Spice jars are held in the 
  -            <a href="http://spice.sf.net/maven">http://spice.sf.net/maven</a> 
  -            repository for Maven usage.
  -            </p>
  +            <a href="http://dist.codehaus.org/spice">Codehaus Repository</a>. 
  +         </p>
          </section>
         <section name="Multi-Container support">
            <p>
  @@ -31,9 +30,9 @@
                  supports type-1 Inversion of Control (IoC).
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/netserve/connection/impl/AvalonConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/impl/AvalonConnectionManager.html">
                     AvalonConnectionManager</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/netserve/connection/ConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/ConnectionManager.html">
                     ConnectionManager</a> interface which is Avalon-compatible.
               </p>
            </subsection>
  @@ -43,9 +42,9 @@
                  supports type-1 Inversion of Control (IoC).
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/netserve/connection/impl/DNAConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/impl/DNAConnectionManager.html">
                     DNAConnectionManager</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/netserve/connection/ConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/ConnectionManager.html">
                     ConnectionManager</a> interface which is DNA-compatible.
               </p>
            </subsection>
  @@ -55,9 +54,9 @@
                  supports type-3 IoC.
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/netserve/connection/impl/PicoConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/impl/PicoConnectionManager.html">
                     PicoConnectionManager</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/netserve/connection/ConnectionManager.html">
  +               <a href="apidocs/org/codehaus/spice/netserve/connection/ConnectionManager.html">
                     ConnectionManager</a> interface which is 
                     <img src="http://www.picocontainer.org/images/pico-compatible.png" alt="Pico-compatible"/>.
               </p>
  
  
  
  1.1                  spice/components/netserve/src/test/org/codehaus/spice/netserve/sockets/impl/SocketTestCase.java
  
  Index: SocketTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.netserve.sockets.impl;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.net.InetAddress;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.net.UnknownHostException;
  import junit.framework.TestCase;
  import org.codehaus.spice.netserve.sockets.ServerSocketFactory;
  import org.codehaus.spice.netserve.sockets.SocketFactory;
  
  /**
   * TestCase for {@link org.codehaus.spice.netserve.sockets.SocketFactory} and {@link org.codehaus.spice.netserve.sockets.ServerSocketFactory}.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:25:07 $
   */
  public class SocketTestCase
      extends TestCase
  {
      private static final int PORT = 1977;
      private static final InetAddress HOST = getLocalHost();
      private static final byte DATA = 23;
  
      public SocketTestCase( final String name )
      {
          super( name );
      }
  
      public void testDefault()
          throws Exception
      {
          final SocketFactory csf = new DefaultSocketFactory();
          final ServerSocketFactory ssf = new DefaultServerSocketFactory();
  
          doSocketPairTest( csf, ssf );
      }
  
      private void doSocketPairTest( final SocketFactory csf, final ServerSocketFactory ssf ) throws IOException
      {
          try
          {
              csf.createSocket( HOST, PORT );
              final String message = "Should not be able to create " +
                  "client socket when server socket not initialized.";
              fail( message );
          }
          catch( IOException e )
          {
          }
  
          final ServerSocket ss1 = ssf.createServerSocket( PORT );
          readWriteTestsOnSingleSocket( ss1, csf );
  
          final ServerSocket ss2 = ssf.createServerSocket( PORT, 1 );
          readWriteTestsOnSingleSocket( ss2, csf );
  
          final ServerSocket ss3 = ssf.createServerSocket( PORT, 1, HOST );
          readWriteTestsOnSingleSocket( ss3, csf );
      }
  
      private void readWriteTestsOnSingleSocket( final ServerSocket serverSocket,
                                                 final SocketFactory csf )
          throws IOException
      {
          final Socket client = csf.createSocket( HOST, PORT );
          final Socket server = serverSocket.accept();
  
          pushPullData( "Testing single socket conn", client, server );
  
          final Socket client2 = csf.createSocket( HOST, PORT, HOST, 0 );
          final Socket server2 = serverSocket.accept();
          pushPullData( "Testing single socket conn2", client2, server2 );
  
          serverSocket.close();
      }
  
      private void pushPullData( final String prefix,
                                 final Socket client,
                                 final Socket server )
          throws IOException
      {
          pushData( prefix + ": c2s", client, server );
          pushData( prefix + ": s2c", server, client );
  
          client.close();
          server.close();
      }
  
      /**
       * Push data from socket1 to socket2.
       */
      private void pushData( final String prefix,
                             final Socket socket1,
                             final Socket socket2 ) throws IOException
      {
          final OutputStream cos = socket1.getOutputStream();
          cos.write( DATA );
          cos.flush();
  
          final InputStream sis = socket2.getInputStream();
          assertEquals( prefix + ": Write/read byte", DATA, sis.read() );
      }
  
      private static InetAddress getLocalHost()
      {
          try
          {
              return InetAddress.getLocalHost();
          }
          catch( UnknownHostException e )
          {
              throw new IllegalStateException( e.toString() );
          }
      }
  }