You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by pg...@apache.org on 2002/10/07 09:16:46 UTC

cvs commit: jakarta-james/src/java/org/apache/james/util/connection ServerConnection.java SimpleConnectionManager.java SimpleConnectionManager.xinfo package.html

pgoldstein    2002/10/07 00:16:46

  Modified:    src/conf james-assembly.xml james-config.xml
  Added:       src/java/org/apache/james/util/connection
                        ServerConnection.java SimpleConnectionManager.java
                        SimpleConnectionManager.xinfo package.html
  Log:
  Added the SimpleConnectionManager and supporting class ServerConnection.
  
  Changed the configuration/assembly -
    i) Replaced tabs with spaces
    ii) Added comments
    iii) Removed AuthService references
    iv) Increased max number of threads in thread pool
    v) Changed ConnectionManager to default to org.apache.james.util.connection.SimpleConnectionManager
    vi) Added commented authRequired element to NNTP server
  
  Revision  Changes    Path
  1.12      +1 -6      jakarta-james/src/conf/james-assembly.xml
  
  Index: james-assembly.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/conf/james-assembly.xml,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- james-assembly.xml	2 Oct 2002 09:53:37 -0000	1.11
  +++ james-assembly.xml	7 Oct 2002 07:16:46 -0000	1.12
  @@ -99,11 +99,6 @@
                role="org.apache.james.nntpserver.repository.NNTPRepository"/>
     </block>
   
  -  <!-- NNTP Authentication Service -->
  -  <block name="nntpauth" class="org.apache.james.nntpserver.AuthServiceImpl" >
  -    <provide name="users-store" role="org.apache.james.services.UsersStore"/>
  -  </block>
  -
     <!-- NNTP Repository -->
     <block name="nntp-repository" class="org.apache.james.nntpserver.repository.NNTPRepositoryImpl" />
   
  @@ -142,7 +137,7 @@
   
     <!-- The Connection Manager block -->
     <block name="connections"
  -         class="org.apache.avalon.cornerstone.blocks.connection.DefaultConnectionManager" >
  +         class="org.apache.james.util.connection.SimpleConnectionManager" >
       <provide name="thread-manager"
                role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
     </block>
  
  
  
  1.34      +92 -49    jakarta-james/src/conf/james-config.xml
  
  Index: james-config.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/conf/james-config.xml,v
  retrieving revision 1.33
  retrieving revision 1.34
  diff -u -r1.33 -r1.34
  --- james-config.xml	27 Sep 2002 16:31:06 -0000	1.33
  +++ james-config.xml	7 Oct 2002 07:16:46 -0000	1.34
  @@ -7,10 +7,10 @@
                                  README!
   
   This configuration file is designed to run without alteration for simple tests.
  -It assumes you have a DNS server on localhost and assigns a root pasword of root.
  +It assumes you have a DNS server on localhost and assigns a root password of root.
   
   In case the defaults do not suit you, the items you are most likely to need to change
  -are preceeded by a CHECKME! or CONFIRM? comment in the left margin.
  +are preceded by a CHECKME! or CONFIRM? comment in the left margin.
   
   For production use you will probably need to make more extensive changes, see
   http://jakarta.apache.org/james/configuration_v2_0.html
  @@ -30,16 +30,16 @@
              If autodetectIP is not FALSE, James will also allow add the IP address for each servername.
              The automatic IP detection is to support RFC 2821, Sec 4.1.3, address literals.
              By default, the servername 'localhost' is specified. This can be removed, if required. -->
  -      <servernames autodetect="TRUE" autodetectIP="TRUE">
  +      <servernames autodetect="true" autodetectIP="true">
            <!--<servername>To override autodetected server names  uncomment this.  </servername> -->
            <servername>localhost</servername>
  -       	<!-- IMPORTANT if you are using fetchpop it is important to include the -->
  -       	<!-- fetched domains here to prevent looping                            -->
  +        <!-- IMPORTANT if you are using fetchpop it is important to include the -->
  +        <!-- fetched domains here to prevent looping                            -->
         </servernames>
   
         <!-- Set whether user names are case sensitive or case insensitive -->
         <!-- Set whether to enable local aliases -->
  -      <usernames ignoreCase="TRUE" enableAliases="TRUE" enableForwarding="TRUE"/>
  +      <usernames ignoreCase="true" enableAliases="true" enableForwarding="true"/>
   
         <!-- The inbox repository is the location for users inboxes -->
         <!-- Default setting: file based repository - enter path ( use  "file:///" for absolute) -->
  @@ -62,22 +62,22 @@
      <!-- fetched domains in the <servernames> section of the <James> block      -->
      <!-- above. fetchpop is disabled by default.                                  -->
      
  -	<fetchpop enabled="false">
  -		<!-- you can have as many fetch tasks as you want to        -->
  -		<!-- but each must have a unique name to identify itself by -->
  -		<fetch name="mydomain.com">
  -			<!-- host name or IP address -->
  -			<host>mail.mydomain.com</host>
  -			<!-- acount login username -->
  -			<user>username</user>
  -			<!-- account login password -->
  -			<password>pass</password>
  -			<!-- Interval to check this account in milliseconds, 600000 is every ten minutes -->
  -			<interval>600000</interval>
  -		</fetch>
  -	</fetchpop>
  -	
  -	
  +    <fetchpop enabled="false">
  +        <!-- you can have as many fetch tasks as you want to        -->
  +        <!-- but each must have a unique name to identify itself by -->
  +        <fetch name="mydomain.com">
  +            <!-- host name or IP address -->
  +            <host>mail.mydomain.com</host>
  +            <!-- acount login username -->
  +            <user>username</user>
  +            <!-- account login password -->
  +            <password>pass</password>
  +            <!-- Interval to check this account in milliseconds, 600000 is every ten minutes -->
  +            <interval>600000</interval>
  +        </fetch>
  +    </fetchpop>
  +    
  +    
      <!-- The James Spool Manager block  -->
      <spoolmanager>
         <!-- number of spool threads -->
  @@ -119,7 +119,7 @@
            <!-- Sample matching to kill a message (send to Null) -->
            <mailet match="RecipientIs=badboy@badhost" class="Null"/>
   
  -         <!-- Send remaining mails to the transport processor for either  local or remote delivery -->
  +         <!-- Send remaining mails to the transport processor for either local or remote delivery -->
            <mailet match="All" class="ToProcessor">
               <processor> transport </processor>
            </mailet>
  @@ -142,7 +142,7 @@
            <!--<mailet match="All" class="NotifyPostmaster"/>-->
         </processor>
   
  -      <!--  Processor CONFIGURATION SAMPLE: transport is a sample custom  processor for local or remote delivery -->
  +      <!--  Processor CONFIGURATION SAMPLE: transport is a sample custom processor for local or remote delivery -->
         <processor name="transport">
   
            <!-- Is the recipient is for a local account, deliver it locally -->
  @@ -153,7 +153,7 @@
               <processor>error</processor>
            </mailet>
   
  -		<!-- CHECKME!    Anti-relay mailet: Add your network address here,
  +        <!-- CHECKME!    Anti-relay mailet: Add your network address here,
                     e.g. "RemoteAddrNotInNetwork=127.0.0.1, abc.de.*, 192.168.0.*"-->
   
            <!-- This matcher-mailet pair can prevent relaying...
  @@ -244,7 +244,7 @@
                  autodetect is TRUE, James will attempt to discover its own name OR
                  use 'localhost'. If autodetect is FALSE, James will use the value
                  given OR 'localhost' -->
  -         <helloName autodetect="TRUE">myMailServer</helloName>
  +         <helloName autodetect="true">myMailServer</helloName>
            <administrator_accounts>
   <!-- CHECKME! Change the default password! -->
   <!-- FILL ME!!!!!!  You must provide a password for your  administrator accounts (cannot be blank) -->
  @@ -254,9 +254,9 @@
         </handler>
      </remotemanager>
   
  -	<!-- The POP3 server is enabled by default -->
  -	<!-- Disabling blocks will stop them from listening, -->
  -	<!-- but does not free as many resources as removing them would -->
  +    <!-- The POP3 server is enabled by default -->
  +    <!-- Disabling blocks will stop them from listening, -->
  +    <!-- but does not free as many resources as removing them would -->
      <pop3server enabled="true">
         <!-- port 995 is the well-known/IANA registered port for POP3S  ie over SSL/TLS -->
         <!-- port 100 is the well-known/IANA registered port for Standard POP3 -->
  @@ -273,14 +273,14 @@
                  autodetect is TRUE, James will attempt to discover its own name OR
                  use 'localhost'. If autodetect is FALSE, James will use the value
                  given OR 'localhost' -->
  -         <helloName autodetect="TRUE">myMailServer</helloName>
  +         <helloName autodetect="true">myMailServer</helloName>
            <connectiontimeout>120000</connectiontimeout>
         </handler>
      </pop3server>
   
  -	<!-- The SMTP server is enabled by default -->
  -	<!-- Disabling blocks will stop them from listening, -->
  -	<!-- but does not free as many resources as removing them would -->
  +    <!-- The SMTP server is enabled by default -->
  +    <!-- Disabling blocks will stop them from listening, -->
  +    <!-- but does not free as many resources as removing them would -->
      <smtpserver enabled="true">
         <port>25</port>
   
  @@ -295,7 +295,7 @@
                autodetect is TRUE, James will attempt to discover its own name OR
                use 'localhost'. If autodetect is FALSE, James will use the value
                given OR 'localhost' -->
  -         <helloName autodetect="TRUE">myMailServer</helloName>
  +         <helloName autodetect="true">myMailServer</helloName>
            <connectiontimeout>360000</connectiontimeout>
            <!--  uncomment this if you want
                  SMTP AUTH support. This is useful if you have users who need to use
  @@ -313,9 +313,9 @@
         </handler>
      </smtpserver>
      
  -   	<!-- The NNTP server is enabled by default -->
  -	<!-- Disabling blocks will stop them from listening, -->
  -	<!-- but does not free as many resources as removing them would -->
  +    <!-- The NNTP server is enabled by default -->
  +    <!-- Disabling blocks will stop them from listening, -->
  +    <!-- but does not free as many resources as removing them would -->
      <nntpserver enabled="true">
         <!-- port 563 is the well-known/IANA registered port for nntp over SSL/TLS -->
         <!-- port 119 is the well-known/IANA registered port for Standard nntp -->
  @@ -332,16 +332,13 @@
               autodetect is TRUE, James will attempt to discover its own name OR
               use 'localhost'. If autodetect is FALSE, James will use the value
               given OR 'localhost' -->
  -         <helloName autodetect="TRUE">myMailServer</helloName>
  +         <helloName autodetect="true">myMailServer</helloName>
            <connectiontimeout>120000</connectiontimeout>
  +          <!-- Set the authRequired value to true to enable authenticated NNTP -->
  +         <authRequired>false</authRequired>
         </handler>
      </nntpserver>
   
  -   <nntpauth>
  -      <!-- make this true, if you want only authenticated users to access NNTP-->
  -      <authRequired>false</authRequired>
  -   </nntpauth>
  -
      <nntp-repository>
         <!-- make this true to disallow posting to all newsgroups-->
         <readOnly>false</readOnly>
  @@ -460,8 +457,8 @@
         User repositories are required for the following purposes:
         - holding information about Users of the James mail server
         - holding lists of users for the listserv mailet
  -      Currently, 2 different storage options are available:
  -      - file-based storage using Java serialisation
  +      Currently, two different storage options are available:
  +      - file-based storage using Java serialization
         - database-backed storage
         (Use of database or file-system is defined on a "per-repository" basis)
         Note: Two user repositories are required for default configuration:
  @@ -533,8 +530,19 @@
         </data-sources>
      </database-connections>
   
  -   <!-- Configuration for Cornerstone Blocks only after here NOTHING BELOW THIS SHOULD NEED CHANGING,
  -    (unless you want secure sockets (TLS)) -->
  +   <!-- Configuration for Cornerstone Services -->
  +   <!-- -->
  +   <!-- For a simple configuration, nothing beneath this line should require -->
  +   <!-- alteration. -->
  +   <!-- -->
  +   <!-- You will need to adjust the Socket Manager service configuration if you want -->
  +   <!-- to enable secure sockets (TLS) for any James service.                        -->
  +   <!-- -->
  +   <!-- Complex or high volume configurations may require changes to the parameters -->
  +   <!-- in this section.  Please read the James and Avalon documentation before -->
  +   <!-- attempting to adjust this section. -->
  +   <!-- -->
  +
      <!-- The Storage block -->
      <objectstorage>
         <repositories>
  @@ -566,7 +574,42 @@
            </repository>
         </repositories>
      </objectstorage>
  +   <!-- The Connection Manager block -->
  +   <!-- -->
  +   <!-- The idle-timeout is the number of milliseconds that it will take for idle -->
  +   <!-- client connections managed by this connection manager to be marked at timed out. -->
  +   <!-- If no value is specified, the value defaults to 5 minutes, 300000 milliseconds -->
  +   <!-- A value of 0 means that client sockets will not timeout. -->
  +   <!-- -->
  +   <!-- The max-connections parameter specifies the maximum number of client connections -->
  +   <!-- that this connection manager will allow per managed server socket. -->
  +   <!-- If no value is specified, the value defaults to 30. -->
  +   <!-- A value of 0 means that there is no limit imposed by the connection manager, although -->
  +   <!-- resource limitations imposed by other components (i.e. max # of threads) may -->
  +   <!-- serve to limit the number of open connections. -->
  +   <!-- -->
  +   <connections>
  +      <idle-timeout>300000<idle-timeout>
  +      <max-connections>30<max-connections>
  +   </connections>
      <!-- The Socket Manager block -->
  +   <!-- -->
  +   <!-- The server-sockets element has a number of factory sub-elements. -->
  +   <!-- Each of the factory elements has a name and class attribute -->
  +   <!-- The name attribute for each factory element must be unique.  -->
  +   <!-- The class attribute is the name of a class that implements the -->
  +   <!-- interface org.apache.avalon.cornerstone.services.ServerSocketFactory -->
  +   <!-- Specific factory elements may require some sub-elements.  This is -->
  +   <!-- factory class dependent. -->
  +   <!-- -->
  +   <!-- The client-sockets element has a number of factory sub-elements. -->
  +   <!-- Each of the factory elements has a name and class attribute -->
  +   <!-- The name attribute for each factory element must be unique.  -->
  +   <!-- The class attribute is the name of a class that implements the -->
  +   <!-- interface org.apache.avalon.cornerstone.services.SocketFactory -->
  +   <!-- Specific factory elements may require some sub-elements.  This is -->
  +   <!-- factory class dependent. -->
  +   <!-- -->
      <sockets>
         <server-sockets>
            <factory name="plain" class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketFactory"/>
  @@ -592,7 +635,7 @@
            <priority>5</priority>
            <!-- are threads daemon threads ? -->
            <is-daemon>false</is-daemon>
  -         <max-threads>40</max-threads>
  +         <max-threads>100</max-threads>
            <!-- these are ignored at the moment but will be fixed in later revisions -->
            <min-threads>20</min-threads>
            <min-spare-threads>20</min-spare-threads>
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/util/connection/ServerConnection.java
  
  Index: ServerConnection.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.james.util.connection;
  
  import java.io.IOException;
  import java.io.InterruptedIOException;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.net.SocketException;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
  import org.apache.avalon.excalibur.thread.ThreadPool;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  
  
  /**
   * Represents a single server socket managed by a connection manager.
   * The connection manager will spawn a single ServerConnection for each
   * server socket that the connection manager is managing.
   *
   * @author Andrei Ivanov
   * @author Peter M. Goldstein <fa...@alum.mit.edu>
   */
  public class ServerConnection extends AbstractLogEnabled
      implements Component, Runnable {
  
      /**
       * This is a hack to deal with the fact that there appears to be
       * no platform-independent way to break out of a ServerSocket
       * accept() call.  On some platforms closing either the ServerSocket
       * itself, or its associated InputStream, causes the accept 
       * method to exit.  Unfortunately, this behavior is not consistent
       * across platforms.  The deal with this, we introduce a polling
       * loop of 20 seconds for the server socket.  This introduces a
       * cost across platforms, but is necessary to maintain cross-platform
       * functionality.
       */
      private static int POLLING_INTERVAL = 20*1000;
  
      /**
       * The server socket which this connection is managing
       */
      private ServerSocket serverSocket;
  
      /**
       * The connection handler factory that generates connection
       * handlers to manage client connections to this server socket
       */
      private ConnectionHandlerFactory handlerFactory;
  
      /**
       * The thread pool used to spawn individual threads used to manage each
       * client connection.
       */
      private ThreadPool connThreadPool;
  
      /**
       * The timeout for client sockets spawned off this connection.
       */
      private int socketTimeout;
  
      /**
       * The maximum number of open client connections that this server
       * connection will allow.
       */
      private int maxOpenConn;
  
      /**
       * A collection of client connection runners.
       */
      private final ArrayList clientConnectionRunners = new ArrayList();    
  
      /**
       * The current number of open client connections.
       */
       private int openConnections = 0;
  
      /**
       * The thread used to manage this server connection.
       */
      private Thread serverConnectionThread;    
  
      /**
       * The sole constructor for a ServerConnection.
       *
       * @param serverSocket the ServerSocket associated with this ServerConnection
       * @param handlerFactory the factory that generates ConnectionHandlers for the client
       *                       connections spawned off this ServerConnection
       * @param threadPool the ThreadPool used to obtain handler threads
       * @param timeout the client idle timeout for this ServerConnection's client connections
       * @param maxOpenConn the maximum number of open client connections allowed for this
       *                    ServerConnection
       */
      public ServerConnection(ServerSocket serverSocket,
                              ConnectionHandlerFactory handlerFactory,
                              ThreadPool threadPool,
                              int timeout,
                              int maxOpenConn) {
          this.serverSocket = serverSocket;
          this.handlerFactory = handlerFactory;
          connThreadPool = threadPool;
          socketTimeout = timeout;
          this.maxOpenConn = maxOpenConn;
      }
  
      /**
       * The dispose operation is called by the owning ConnectionManager 
       * at the end of its lifecycle.  Cleans up the server connection, forcing
       * everything to finish.
       */
      public void dispose() {
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Disposing server connection..." + this.toString());
          }
          synchronized( this ) {
              if( null != serverConnectionThread ) {
                  // Execution of this block means that the run() method
                  // hasn't finished yet.  So we interrupt the thread
                  // to terminate run() and wait for the run() method
                  // to finish.  The notifyAll() at the end of run() will
                  // wake this thread and allow dispose() to end.
                  Thread thread = serverConnectionThread;
                  serverConnectionThread = null;
                  thread.interrupt();
                  try {
                      serverSocket.close();
                  } catch (IOException ie) {
                      // Ignored - we're doing this to break out of the 
                      // accept.  This minimizes the time required to
                      // shutdown the server.  Unfortunately, this is
                      // not guaranteed to work on all platforms.  See
                      // the comments for POLLING_INTERVAL
                  }
                  try {
                      if (POLLING_INTERVAL > 0) {
                          wait(2L*POLLING_INTERVAL);
                      } else {
                          wait();
                      }
                  } catch (InterruptedException ie) {
                      // Expected - just complete dispose()
                  }
              }
          }
  
          getLogger().debug("Closed server connection - cleaning up clients - " + this.toString());
  
          synchronized (clientConnectionRunners) {
              Iterator runnerIterator = clientConnectionRunners.iterator();
              while( runnerIterator.hasNext() )
              {
                  ClientConnectionRunner runner = (ClientConnectionRunner)runnerIterator.next();
                  runner.dispose();
                  runner = null;
              }
              clientConnectionRunners.clear();
              openConnections = 0;
          }
  
          getLogger().debug("Cleaned up clients - " + this.toString());
  
      }
  
      /**
       * Adds a ClientConnectionRunner to the set managed by this ServerConnection object.
       *
       * @param clientConnectionRunner the ClientConnectionRunner to be added
       */
      private void addClientConnectionRunner(ClientConnectionRunner clientConnectionRunner) {
          synchronized (clientConnectionRunners) {
              clientConnectionRunners.add(clientConnectionRunner);
              openConnections++;
          }
      }
  
      /**
       * Removes a ClientConnectionRunner from the set managed by this ServerConnection object.
       *
       * @param clientConnectionRunner the ClientConnectionRunner to be removed
       */
      private void removeClientConnectionRunner(ClientConnectionRunner clientConnectionRunner) {
          synchronized (clientConnectionRunners) {
              clientConnectionRunners.remove(clientConnectionRunner);
              openConnections--;
          }
      }
  
      /**
       * Provides the body for the thread of execution for a ServerConnection.
       * Connections made to the server socket are passed to an appropriate,
       * newly created, ClientConnectionRunner
       */
      public void run() {
          serverConnectionThread = Thread.currentThread();
  
          int ioExceptionCount = 0;
          try {
              serverSocket.setSoTimeout(POLLING_INTERVAL);
          } catch (SocketException se) {
              // Ignored - for the moment
          }
          while( null != serverConnectionThread && !serverConnectionThread.isInterrupted() ) {
              try {
                  Socket clientSocket = null;
                  try {
                      clientSocket = serverSocket.accept();
                  } catch( InterruptedIOException iioe ) {
                      // This exception is expected upon ServerConnection shutdown.
                      // See the POLLING_INTERVAL comment
                      continue;
                  } catch( IOException se ) {
                      if (ioExceptionCount > 0) {
                          getLogger().error( "Fatal exception while listening on server socket.  Terminating connection.", se );
                          break;
                      } else {
                          continue;
                      }
                  } catch( SecurityException se ) {
                      getLogger().error( "Fatal exception while listening on server socket.  Terminating connection.", se );
                      break;
                  }
                  ClientConnectionRunner runner = null;
                  synchronized (clientConnectionRunners) {
                      if ((maxOpenConn > 0) && (openConnections >= maxOpenConn)) {
                          if (getLogger().isWarnEnabled()) {
                              getLogger().warn("Maximum number of open connections exceeded - refusing connection.  Current number of connections is " + openConnections);
                          }
                          try {
                              clientSocket.close();
                          } catch (IOException ignored) {
                              // We ignore this exception, as we already have an error condition.
                          }
                          continue;
                      } else {
                          clientSocket.setSoTimeout(socketTimeout);
                          runner =
                              new ClientConnectionRunner(clientSocket, handlerFactory);
                      }
                  }
                  setupLogger( runner );
                  connThreadPool.execute( runner );
              } catch( IOException ioe ) {
                  getLogger().error( "Exception accepting connection", ioe );
              } catch( Exception e ) {
                  getLogger().error( "Exception executing client connection runner: " + e.getMessage() );
              }
          }
          synchronized( this ) {
              serverConnectionThread = null;
              notifyAll();
          }
      }
  
      /**
       * An inner class to provide the actual body of the thread of execution
       * that occurs upon a client connection.
       *
       * @author Andrei Ivanov
       * @author Peter M. Goldstein <fa...@alum.mit.edu>
       */
      class ClientConnectionRunner extends AbstractLogEnabled
          implements Runnable, Component  {
  
          /**
           * The Socket that this client connection is using for transport.
           */
          private Socket clientSocket;
  
          /**
           * The thread of execution associated with this client connection.
           */
          private Thread clientSocketThread;
  
          /**
           * The ConnectionHandlerFactory that generates a ConnectionHandler for
           * this client connection.
           */
          private ConnectionHandlerFactory clientConnectionHandlerFactory;
        
          /**
           * The constructor for a ClientConnectionRunner.
           *
           * @param socket the client socket associated with this ClientConnectionRunner
           * @param handlerFactory the factory that generates ConnectionHandlers for this
           *                       connection
           */
          public ClientConnectionRunner(Socket socket,
                                        ConnectionHandlerFactory handlerFactory) {
              clientSocket = socket;
              clientConnectionHandlerFactory = handlerFactory;
          }
        
          /**
           * The dispose operation that terminates the runner.  Should only be
           * called by the ServerConnection that owns the ClientConnectionRunner
           */
          public void dispose() {
              synchronized( this ) {
                  if (null != clientSocketThread) {
                      // Execution of this block means that the run() method
                      // hasn't finished yet.  So we interrupt the thread
                      // to terminate run() and wait for the run() method
                      // to finish.  The notifyAll() at the end of run() will
                      // wake this thread and allow dispose() to end.
                      clientSocketThread.interrupt();
                      clientSocketThread = null;
                      try {
                          wait();
                      } catch (InterruptedException ie) {
                          // Expected - return from the method
                      }
                  }
              }
          }
  
          /**
           * Provides the body for the thread of execution dealing with a particular client
           * connection.  An appropriate ConnectionHandler is created, applied, executed, 
           * and released. 
           */
          public void run() {
              ConnectionHandler handler = null;
              try {
                  clientSocketThread = Thread.currentThread();
                  ServerConnection.this.addClientConnectionRunner(this);
  
                  handler = clientConnectionHandlerFactory.createConnectionHandler();
                  String connectionString = null;
                  if( getLogger().isDebugEnabled() ) {
                      connectionString = getConnectionString();
                      String message = "Starting " + connectionString;
                      getLogger().debug( message );
                  }
  
                  handler.handleConnection(clientSocket);
  
                  if( getLogger().isDebugEnabled() ) {
                      String message = "Ending " + connectionString;
                      getLogger().debug( message );
                  }
              } catch( Exception e ) {
                  getLogger().warn( "Error handling connection", e );
              } finally {
      
                  // Close the underlying socket
                  try {
                      clientSocket.close();
                  } catch( IOException ioe ) {
                      getLogger().warn( "Error shutting down connection", ioe );
                  }
      
                  // Release the handler and kill the reference to the handler factory
                  if (handler != null) {
                      clientConnectionHandlerFactory.releaseConnectionHandler( handler );
                      handler = null;
                  }
                  clientConnectionHandlerFactory = null;
  
                  // Remove this runner from the list of active connections.
                  ServerConnection.this.removeClientConnectionRunner(this);
  
                  // Null out the thread, notify other threads to encourage
                  // a context switch
                  synchronized( this ) {
                      clientSocketThread = null;
                      notifyAll();
                  }
              }
          }
  
          /**
           * Helper method to return a formatted string with connection transport information.
           *
           * @return a formatted string
           */
          private String getConnectionString() {
              if (clientSocket == null) {
                  return "invalid socket";
              }
              StringBuffer connectionBuffer
                  = new StringBuffer(256)
                      .append("connection on ")
                      .append(clientSocket.getLocalAddress().getHostAddress().toString())
                      .append(":")
                      .append(clientSocket.getLocalPort())
                      .append(" from ")
                      .append(clientSocket.getInetAddress().getHostAddress().toString())
                      .append(":")
                      .append(clientSocket.getPort());
              return connectionBuffer.toString();
          }
      }
  }
  
  
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/util/connection/SimpleConnectionManager.java
  
  Index: SimpleConnectionManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.util.connection;
  
  import java.net.ServerSocket;
  import java.util.HashMap;
  
  import org.apache.avalon.excalibur.thread.ThreadPool;
  
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
  import org.apache.avalon.cornerstone.services.connection.ConnectionManager;
  import org.apache.avalon.cornerstone.services.threads.ThreadManager;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  
  
  /**
   * An implementation of ConnectionManager that supports configurable
   * idle timeouts and a configurable value for the maximum number of 
   * client connections to a particular port.
   *
   * @author Andrei Ivanov
   * @author Peter M. Goldstein <fa...@alum.mit.edu>
   */
  public class SimpleConnectionManager extends AbstractLogEnabled
      implements ConnectionManager, Composable, Configurable, Disposable {
  
      /**
       * The default value for client socket idle timeouts.  The
       * Java default is 0, meaning no timeout.  That's dangerous
       * for a connection handler like this one, because it can
       * easily lead to consumption of network resources.  So we
       * allow users to configure the system to allow no timeout,
       * but if no timeout is specified in the configuration, we
       * use a timeout of 5 minutes.
       */
      private static final int DEFAULT_SOCKET_TIMEOUT = 5 * 60 * 1000;
  
      /**
       * The default value for the maximum number of allowed client
       * connections.
       */
      private static final int DEFAULT_MAX_CONNECTIONS = 30;
  
      /**
       * The map of connection name / server connections managed by this connection
       * manager.
       */
      private final HashMap connectionMap = new HashMap();
    
      /**
       * The idle timeout for the individual sockets spawed from the server socket.
       */
      protected int timeout = 0;
  
      /**
       * The maximum number of client connections allowed per server connection.
       */
      protected int maxOpenConn = 0;
  
      /**
       * The ThreadManager component that is used to provide a default thread pool.
       */
      private ThreadManager threadManager;
  
      /**
       * Whether the SimpleConnectionManager has been disposed.
       */
      private volatile boolean disposed = false;
  
      /**
       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
       */
      public void configure(final Configuration configuration) throws ConfigurationException {
          timeout = configuration.getChild("idle-timeout").getValueAsInteger(DEFAULT_SOCKET_TIMEOUT);
          maxOpenConn = configuration.getChild("max-connections").getValueAsInteger(DEFAULT_MAX_CONNECTIONS);
  
          if (timeout < 0) {
              StringBuffer exceptionBuffer =
                  new StringBuffer(128)
                      .append("Specified socket timeout value of ")
                      .append(timeout)
                      .append(" is not a legal value.");
              throw new ConfigurationException(exceptionBuffer.toString());
          } 
  
          if (maxOpenConn < 0) {
              StringBuffer exceptionBuffer =
                  new StringBuffer(128)
                      .append("Specified maximum number of open connections of ")
                      .append(maxOpenConn)
                      .append(" is not a legal value.");
              throw new ConfigurationException(exceptionBuffer.toString());
          } 
  
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Connection timeout is " 
                               + (timeout == 0 ? "unlimited" : Long.toString(timeout)));
              getLogger().debug("The maximum number of simultaneously open connections is " 
                               + (maxOpenConn == 0 ? "unlimited" : Integer.toString(maxOpenConn)));
          }
      }
  
      /**
       * @see org.apache.avalon.framework.component.Composable#compose(ComponentManager)
       */
      public void compose(ComponentManager componentManager) 
          throws ComponentException {
          threadManager = (ThreadManager)componentManager.lookup( ThreadManager.ROLE );
      }
  
      /**
       * Disconnects all the underlying ServerConnections
       */
      public void dispose() {
          disposed = true;
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Starting SimpleConnectionManager dispose...");
          }
          final String[] names = (String[])connectionMap.keySet().toArray( new String[ 0 ] );
          for( int i = 0; i < names.length; i++ ) {
              try {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("Disconnecting ServerConnection " + names[i]);
                  }
                  disconnect( names[ i ], true);
              } catch( final Exception e ) {
                  getLogger().warn( "Error disconnecting " + names[ i ], e );
              }
          }
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Finishing SimpleConnectionManager dispose...");
          }
      }
    
      /**
       * Start managing a connection.
       * Management involves accepting connections and farming them out to threads
       * from pool to be handled.
       *
       * @param name the name of connection
       * @param socket the ServerSocket from which to
       * @param handlerFactory the factory from which to acquire handlers
       * @param threadPool the thread pool to use
       * @exception Exception if an error occurs
       */
      public void connect( String name,
                           ServerSocket socket,
                           ConnectionHandlerFactory handlerFactory,
                           ThreadPool threadPool )
          throws Exception {
  
          if (disposed) {
              throw new IllegalStateException("Connection manager has already been shutdown.");
          }
          if( null != connectionMap.get( name ) ) {
              throw new IllegalArgumentException( "Connection already exists with name " +
                                                  name );
          }
      
          ServerConnection runner = new ServerConnection(socket, handlerFactory, threadPool, timeout, maxOpenConn);
          setupLogger( runner );
          connectionMap.put( name, runner );
          threadPool.execute(runner);
      }
  
      /**
       * Start managing a connection.
       * This is similar to other connect method except that it uses default thread pool.
       *
       * @param name the name of connection
       * @param socket the ServerSocket from which to
       * @param handlerFactory the factory from which to acquire handlers
       * @exception Exception if an error occurs
       */
      public void connect( String name,
                           ServerSocket socket,
                           ConnectionHandlerFactory handlerFactory )
          throws Exception
      {
          connect( name, socket, handlerFactory, threadManager.getDefaultThreadPool() );
      }
  
    
      /**
       * This shuts down all handlers and socket, waiting for each to gracefully shutdown.
       *
       * @param name the name of connection
       * @exception Exception if an error occurs
       */
      public void disconnect( final String name )
          throws Exception {
  
          disconnect( name, false );
      }
    
      /**
       * This shuts down a connection.
       * If tearDown is true then it will forcefully the connection and try
       * to return as soon as possible. Otherwise it will behave the same as
       * void disconnect( String name );
       *
       * @param name the name of connection
       * @param tearDown if true will forcefully tear down all handlers
       * @exception Exception if an error occurs
       */
      public void disconnect( final String name, final boolean tearDown )
          throws Exception {
  
          ServerConnection connection = (ServerConnection)connectionMap.remove( name );
          if( null == connection ) {
              throw new IllegalArgumentException( "No such connection with name " +
                                                  name );
          }
  
          // TODO: deal with tear down
          connection.dispose();
      }
    
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/util/connection/SimpleConnectionManager.xinfo
  
  Index: SimpleConnectionManager.xinfo
  ===================================================================
  <?xml version="1.0"?>
  
  
  <blockinfo>
  
    <!-- section to describe block -->
    <block>
      <name>SimpleConnectionManager</name>
      <version>1.0</version>
    </block>
  
    <!-- services that are offered by this block -->
    <services>
      <service name="org.apache.avalon.cornerstone.services.connection.ConnectionManager"/>
    </services>
  
    <!-- services that are required by this block -->
    <dependencies>
      <dependency>
        <service name="org.apache.avalon.cornerstone.services.threads.ThreadManager"/>
      </dependency>
   </dependencies>
  
  </blockinfo>
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/util/connection/package.html
  
  Index: package.html
  ===================================================================
  <body>
  <p>Provides classes that implement Avalon Cornerstone connection services.  It would be desirable to have these classes eventually moved to Cornerstone.</p>
  </body>
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: cvs commit: jakarta-james/src/java/org/apache/james/util/connection ServerConnection.java SimpleConnectionManager.java SimpleConnectionManager.xinfo package.html

Posted by "Peter M. Goldstein" <pe...@yahoo.com>.
Nathan,

Thanks.  I'll apply it.  Don't know how I left out the '/' in the config
file I checked in.

--Peter

> -----Original Message-----
> From: Nathan Carter [mailto:nathancarter@gmx.net]
> Sent: Tuesday, October 08, 2002 3:05 PM
> To: James Developers List
> Subject: Re: cvs commit: jakarta-
> james/src/java/org/apache/james/util/connection ServerConnection.java
> SimpleConnectionManager.java SimpleConnectionManager.xinfo
package.html
> 
> Peter,
> 
> Current HEAD compiles fine, but there's a parsing error at runtime due
> to a couple of typos in src/conf/james-config.xml - here is the patch.
> 
> Nathan Carter
> 
> 
> pgoldstein@apache.org wrote:
> 
> >pgoldstein    2002/10/07 00:16:46
> >
> >  Modified:    src/conf james-assembly.xml james-config.xml
> >  Added:       src/java/org/apache/james/util/connection
> >                        ServerConnection.java
> SimpleConnectionManager.java
> >                        SimpleConnectionManager.xinfo package.html
> >  Log:
> >  Added the SimpleConnectionManager and supporting class
> ServerConnection.
> >
> >  Changed the configuration/assembly -
> >    i) Replaced tabs with spaces
> >    ii) Added comments
> >    iii) Removed AuthService references
> >    iv) Increased max number of threads in thread pool
> >    v) Changed ConnectionManager to default to
> org.apache.james.util.connection.SimpleConnectionManager
> >    vi) Added commented authRequired element to NNTP server
> >
> >  Revision  Changes    Path
> >  1.12      +1 -6      jakarta-james/src/conf/james-assembly.xml
> >
> >  Index: james-assembly.xml
> >  ===================================================================
> >  RCS file: /home/cvs/jakarta-james/src/conf/james-assembly.xml,v
> >  retrieving revision 1.11
> >  retrieving revision 1.12
> >  diff -u -r1.11 -r1.12
> >  --- james-assembly.xml	2 Oct 2002 09:53:37 -0000	1.11
> >  +++ james-assembly.xml	7 Oct 2002 07:16:46 -0000	1.12
> >  @@ -99,11 +99,6 @@
> >
> role="org.apache.james.nntpserver.repository.NNTPRepository"/>
> >     </block>
> >
> >  -  <!-- NNTP Authentication Service -->
> >  -  <block name="nntpauth"
> class="org.apache.james.nntpserver.AuthServiceImpl" >
> >  -    <provide name="users-store"
> role="org.apache.james.services.UsersStore"/>
> >  -  </block>
> >  -
> >     <!-- NNTP Repository -->
> >     <block name="nntp-repository"
> class="org.apache.james.nntpserver.repository.NNTPRepositoryImpl" />
> >
> >  @@ -142,7 +137,7 @@
> >
> >     <!-- The Connection Manager block -->
> >     <block name="connections"
> >  -
>
class="org.apache.avalon.cornerstone.blocks.connection.DefaultConnection
Ma
> nager" >
> >  +
> class="org.apache.james.util.connection.SimpleConnectionManager" >
> >       <provide name="thread-manager"
> >
> role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
> >     </block>
> >
> >
> >
> >  1.34      +92 -49    jakarta-james/src/conf/james-config.xml
> >
> >  Index: james-config.xml
> >  ===================================================================
> >  RCS file: /home/cvs/jakarta-james/src/conf/james-config.xml,v
> >  retrieving revision 1.33
> >  retrieving revision 1.34
> >  diff -u -r1.33 -r1.34
> >  --- james-config.xml	27 Sep 2002 16:31:06 -0000	1.33
> >  +++ james-config.xml	7 Oct 2002 07:16:46 -0000	1.34
> >  @@ -7,10 +7,10 @@
> >                                  README!
> >
> >   This configuration file is designed to run without alteration for
> simple tests.
> >  -It assumes you have a DNS server on localhost and assigns a root
> pasword of root.
> >  +It assumes you have a DNS server on localhost and assigns a root
> password of root.
> >
> >   In case the defaults do not suit you, the items you are most
likely to
> need to change
> >  -are preceeded by a CHECKME! or CONFIRM? comment in the left
margin.
> >  +are preceded by a CHECKME! or CONFIRM? comment in the left margin.
> >
> >   For production use you will probably need to make more extensive
> changes, see
> >   http://jakarta.apache.org/james/configuration_v2_0.html
> >  @@ -30,16 +30,16 @@
> >              If autodetectIP is not FALSE, James will also allow add
the
> IP address for each servername.
> >              The automatic IP detection is to support RFC 2821, Sec
> 4.1.3, address literals.
> >              By default, the servername 'localhost' is specified.
This
> can be removed, if required. -->
> >  -      <servernames autodetect="TRUE" autodetectIP="TRUE">
> >  +      <servernames autodetect="true" autodetectIP="true">
> >            <!--<servername>To override autodetected server names
> uncomment this.  </servername> -->
> >            <servername>localhost</servername>
> >  -       	<!-- IMPORTANT if you are using fetchpop it is important
to
> include the -->
> >  -       	<!-- fetched domains here to prevent looping
> -->
> >  +        <!-- IMPORTANT if you are using fetchpop it is important
to
> include the -->
> >  +        <!-- fetched domains here to prevent looping
> -->
> >         </servernames>
> >
> >         <!-- Set whether user names are case sensitive or case
> insensitive -->
> >         <!-- Set whether to enable local aliases -->
> >  -      <usernames ignoreCase="TRUE" enableAliases="TRUE"
> enableForwarding="TRUE"/>
> >  +      <usernames ignoreCase="true" enableAliases="true"
> enableForwarding="true"/>
> >
> >         <!-- The inbox repository is the location for users inboxes
-->
> >         <!-- Default setting: file based repository - enter path (
use
> "file:///" for absolute) -->
> >  @@ -62,22 +62,22 @@
> >      <!-- fetched domains in the <servernames> section of the
<James>
> block      -->
> >      <!-- above. fetchpop is disabled by default.
> -->
> >
> >  -	<fetchpop enabled="false">
> >  -		<!-- you can have as many fetch tasks as you want to
--
> >
> >  -		<!-- but each must have a unique name to identify itself
by --
> >
> >  -		<fetch name="mydomain.com">
> >  -			<!-- host name or IP address -->
> >  -			<host>mail.mydomain.com</host>
> >  -			<!-- acount login username -->
> >  -			<user>username</user>
> >  -			<!-- account login password -->
> >  -			<password>pass</password>
> >  -			<!-- Interval to check this account in
milliseconds,
> 600000 is every ten minutes -->
> >  -			<interval>600000</interval>
> >  -		</fetch>
> >  -	</fetchpop>
> >  -
> >  -
> >  +    <fetchpop enabled="false">
> >  +        <!-- you can have as many fetch tasks as you want to
--
> >
> >  +        <!-- but each must have a unique name to identify itself
by --
> >
> >  +        <fetch name="mydomain.com">
> >  +            <!-- host name or IP address -->
> >  +            <host>mail.mydomain.com</host>
> >  +            <!-- acount login username -->
> >  +            <user>username</user>
> >  +            <!-- account login password -->
> >  +            <password>pass</password>
> >  +            <!-- Interval to check this account in milliseconds,
> 600000 is every ten minutes -->
> >  +            <interval>600000</interval>
> >  +        </fetch>
> >  +    </fetchpop>
> >  +
> >  +
> >      <!-- The James Spool Manager block  -->
> >      <spoolmanager>
> >         <!-- number of spool threads -->
> >  @@ -119,7 +119,7 @@
> >            <!-- Sample matching to kill a message (send to Null) -->
> >            <mailet match="RecipientIs=badboy@badhost" class="Null"/>
> >
> >  -         <!-- Send remaining mails to the transport processor for
> either  local or remote delivery -->
> >  +         <!-- Send remaining mails to the transport processor for
> either local or remote delivery -->
> >            <mailet match="All" class="ToProcessor">
> >               <processor> transport </processor>
> >            </mailet>
> >  @@ -142,7 +142,7 @@
> >            <!--<mailet match="All" class="NotifyPostmaster"/>-->
> >         </processor>
> >
> >  -      <!--  Processor CONFIGURATION SAMPLE: transport is a sample
> custom  processor for local or remote delivery -->
> >  +      <!--  Processor CONFIGURATION SAMPLE: transport is a sample
> custom processor for local or remote delivery -->
> >         <processor name="transport">
> >
> >            <!-- Is the recipient is for a local account, deliver it
> locally -->
> >  @@ -153,7 +153,7 @@
> >               <processor>error</processor>
> >            </mailet>
> >
> >  -		<!-- CHECKME!    Anti-relay mailet: Add your network
address
> here,
> >  +        <!-- CHECKME!    Anti-relay mailet: Add your network
address
> here,
> >                     e.g. "RemoteAddrNotInNetwork=127.0.0.1,
abc.de.*,
> 192.168.0.*"-->
> >
> >            <!-- This matcher-mailet pair can prevent relaying...
> >  @@ -244,7 +244,7 @@
> >                  autodetect is TRUE, James will attempt to discover
its
> own name OR
> >                  use 'localhost'. If autodetect is FALSE, James will
use
> the value
> >                  given OR 'localhost' -->
> >  -         <helloName autodetect="TRUE">myMailServer</helloName>
> >  +         <helloName autodetect="true">myMailServer</helloName>
> >            <administrator_accounts>
> >   <!-- CHECKME! Change the default password! -->
> >   <!-- FILL ME!!!!!!  You must provide a password for your
> administrator accounts (cannot be blank) -->
> >  @@ -254,9 +254,9 @@
> >         </handler>
> >      </remotemanager>
> >
> >  -	<!-- The POP3 server is enabled by default -->
> >  -	<!-- Disabling blocks will stop them from listening, -->
> >  -	<!-- but does not free as many resources as removing them would
-->
> >  +    <!-- The POP3 server is enabled by default -->
> >  +    <!-- Disabling blocks will stop them from listening, -->
> >  +    <!-- but does not free as many resources as removing them
would --
> >
> >      <pop3server enabled="true">
> >         <!-- port 995 is the well-known/IANA registered port for
POP3S
> ie over SSL/TLS -->
> >         <!-- port 100 is the well-known/IANA registered port for
> Standard POP3 -->
> >  @@ -273,14 +273,14 @@
> >                  autodetect is TRUE, James will attempt to discover
its
> own name OR
> >                  use 'localhost'. If autodetect is FALSE, James will
use
> the value
> >                  given OR 'localhost' -->
> >  -         <helloName autodetect="TRUE">myMailServer</helloName>
> >  +         <helloName autodetect="true">myMailServer</helloName>
> >            <connectiontimeout>120000</connectiontimeout>
> >         </handler>
> >      </pop3server>
> >
> >  -	<!-- The SMTP server is enabled by default -->
> >  -	<!-- Disabling blocks will stop them from listening, -->
> >  -	<!-- but does not free as many resources as removing them would
-->
> >  +    <!-- The SMTP server is enabled by default -->
> >  +    <!-- Disabling blocks will stop them from listening, -->
> >  +    <!-- but does not free as many resources as removing them
would --
> >
> >      <smtpserver enabled="true">
> >         <port>25</port>
> >
> >  @@ -295,7 +295,7 @@
> >                autodetect is TRUE, James will attempt to discover
its
> own name OR
> >                use 'localhost'. If autodetect is FALSE, James will
use
> the value
> >                given OR 'localhost' -->
> >  -         <helloName autodetect="TRUE">myMailServer</helloName>
> >  +         <helloName autodetect="true">myMailServer</helloName>
> >            <connectiontimeout>360000</connectiontimeout>
> >            <!--  uncomment this if you want
> >                  SMTP AUTH support. This is useful if you have users
who
> need to use
> >  @@ -313,9 +313,9 @@
> >         </handler>
> >      </smtpserver>
> >
> >  -   	<!-- The NNTP server is enabled by default -->
> >  -	<!-- Disabling blocks will stop them from listening, -->
> >  -	<!-- but does not free as many resources as removing them would
-->
> >  +    <!-- The NNTP server is enabled by default -->
> >  +    <!-- Disabling blocks will stop them from listening, -->
> >  +    <!-- but does not free as many resources as removing them
would --
> >
> >      <nntpserver enabled="true">
> >         <!-- port 563 is the well-known/IANA registered port for
nntp
> over SSL/TLS -->
> >         <!-- port 119 is the well-known/IANA registered port for
> Standard nntp -->
> >  @@ -332,16 +332,13 @@
> >               autodetect is TRUE, James will attempt to discover its
own
> name OR
> >               use 'localhost'. If autodetect is FALSE, James will
use
> the value
> >               given OR 'localhost' -->
> >  -         <helloName autodetect="TRUE">myMailServer</helloName>
> >  +         <helloName autodetect="true">myMailServer</helloName>
> >            <connectiontimeout>120000</connectiontimeout>
> >  +          <!-- Set the authRequired value to true to enable
> authenticated NNTP -->
> >  +         <authRequired>false</authRequired>
> >         </handler>
> >      </nntpserver>
> >
> >  -   <nntpauth>
> >  -      <!-- make this true, if you want only authenticated users to
> access NNTP-->
> >  -      <authRequired>false</authRequired>
> >  -   </nntpauth>
> >  -
> >      <nntp-repository>
> >         <!-- make this true to disallow posting to all newsgroups-->
> >         <readOnly>false</readOnly>
> >  @@ -460,8 +457,8 @@
> >         User repositories are required for the following purposes:
> >         - holding information about Users of the James mail server
> >         - holding lists of users for the listserv mailet
> >  -      Currently, 2 different storage options are available:
> >  -      - file-based storage using Java serialisation
> >  +      Currently, two different storage options are available:
> >  +      - file-based storage using Java serialization
> >         - database-backed storage
> >         (Use of database or file-system is defined on a
"per-repository"
> basis)
> >         Note: Two user repositories are required for default
> configuration:
> >  @@ -533,8 +530,19 @@
> >         </data-sources>
> >      </database-connections>
> >
> >  -   <!-- Configuration for Cornerstone Blocks only after here
NOTHING
> BELOW THIS SHOULD NEED CHANGING,
> >  -    (unless you want secure sockets (TLS)) -->
> >  +   <!-- Configuration for Cornerstone Services -->
> >  +   <!-- -->
> >  +   <!-- For a simple configuration, nothing beneath this line
should
> require -->
> >  +   <!-- alteration. -->
> >  +   <!-- -->
> >  +   <!-- You will need to adjust the Socket Manager service
> configuration if you want -->
> >  +   <!-- to enable secure sockets (TLS) for any James service.
> -->
> >  +   <!-- -->
> >  +   <!-- Complex or high volume configurations may require changes
to
> the parameters -->
> >  +   <!-- in this section.  Please read the James and Avalon
> documentation before -->
> >  +   <!-- attempting to adjust this section. -->
> >  +   <!-- -->
> >  +
> >      <!-- The Storage block -->
> >      <objectstorage>
> >         <repositories>
> >  @@ -566,7 +574,42 @@
> >            </repository>
> >         </repositories>
> >      </objectstorage>
> >  +   <!-- The Connection Manager block -->
> >  +   <!-- -->
> >  +   <!-- The idle-timeout is the number of milliseconds that it
will
> take for idle -->
> >  +   <!-- client connections managed by this connection manager to
be
> marked at timed out. -->
> >  +   <!-- If no value is specified, the value defaults to 5 minutes,
> 300000 milliseconds -->
> >  +   <!-- A value of 0 means that client sockets will not timeout.
-->
> >  +   <!-- -->
> >  +   <!-- The max-connections parameter specifies the maximum number
of
> client connections -->
> >  +   <!-- that this connection manager will allow per managed server
> socket. -->
> >  +   <!-- If no value is specified, the value defaults to 30. -->
> >  +   <!-- A value of 0 means that there is no limit imposed by the
> connection manager, although -->
> >  +   <!-- resource limitations imposed by other components (i.e. max
#
> of threads) may -->
> >  +   <!-- serve to limit the number of open connections. -->
> >  +   <!-- -->
> >  +   <connections>
> >  +      <idle-timeout>300000<idle-timeout>
> >  +      <max-connections>30<max-connections>
> >  +   </connections>
> >      <!-- The Socket Manager block -->
> >  +   <!-- -->
> >  +   <!-- The server-sockets element has a number of factory sub-
> elements. -->
> >  +   <!-- Each of the factory elements has a name and class
attribute --
> >
> >  +   <!-- The name attribute for each factory element must be
unique.  -
> ->
> >  +   <!-- The class attribute is the name of a class that implements
the
> -->
> >  +   <!-- interface
> org.apache.avalon.cornerstone.services.ServerSocketFactory -->
> >  +   <!-- Specific factory elements may require some sub-elements.
This
> is -->
> >  +   <!-- factory class dependent. -->
> >  +   <!-- -->
> >  +   <!-- The client-sockets element has a number of factory sub-
> elements. -->
> >  +   <!-- Each of the factory elements has a name and class
attribute --
> >
> >  +   <!-- The name attribute for each factory element must be
unique.  -
> ->
> >  +   <!-- The class attribute is the name of a class that implements
the
> -->
> >  +   <!-- interface
org.apache.avalon.cornerstone.services.SocketFactory
> -->
> >  +   <!-- Specific factory elements may require some sub-elements.
This
> is -->
> >  +   <!-- factory class dependent. -->
> >  +   <!-- -->
> >      <sockets>
> >         <server-sockets>
> >            <factory name="plain"
>
class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketF
ac
> tory"/>
> >  @@ -592,7 +635,7 @@
> >            <priority>5</priority>
> >            <!-- are threads daemon threads ? -->
> >            <is-daemon>false</is-daemon>
> >  -         <max-threads>40</max-threads>
> >  +         <max-threads>100</max-threads>
> >            <!-- these are ignored at the moment but will be fixed in
> later revisions -->
> >            <min-threads>20</min-threads>
> >            <min-spare-threads>20</min-spare-threads>
> >
> >
> >
> >  1.1                  jakarta-
> james/src/java/org/apache/james/util/connection/ServerConnection.java
> >
> >  Index: ServerConnection.java
> >  ===================================================================
> >  /*
> >   * Copyright (C) The Apache Software Foundation. All rights
reserved.
> >   *
> >   * This software is published under the terms of the Apache
Software
> License
> >   * version 1.1, a copy of which has been included with this
> distribution in
> >   * the LICENSE.txt file.
> >   */
> >  package org.apache.james.util.connection;
> >
> >  import java.io.IOException;
> >  import java.io.InterruptedIOException;
> >  import java.net.ServerSocket;
> >  import java.net.Socket;
> >  import java.net.SocketException;
> >  import java.util.ArrayList;
> >  import java.util.Iterator;
> >  import java.util.List;
> >
> >  import
> org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
> >  import
>
org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFacto
ry
> ;
> >  import org.apache.avalon.excalibur.thread.ThreadPool;
> >  import org.apache.avalon.framework.component.Component;
> >  import org.apache.avalon.framework.logger.AbstractLogEnabled;
> >
> >
> >  /**
> >   * Represents a single server socket managed by a connection
manager.
> >   * The connection manager will spawn a single ServerConnection for
each
> >   * server socket that the connection manager is managing.
> >   *
> >   * @author Andrei Ivanov
> >   * @author Peter M. Goldstein <fa...@alum.mit.edu>
> >   */
> >  public class ServerConnection extends AbstractLogEnabled
> >      implements Component, Runnable {
> >
> >      /**
> >       * This is a hack to deal with the fact that there appears to
be
> >       * no platform-independent way to break out of a ServerSocket
> >       * accept() call.  On some platforms closing either the
> ServerSocket
> >       * itself, or its associated InputStream, causes the accept
> >       * method to exit.  Unfortunately, this behavior is not
consistent
> >       * across platforms.  The deal with this, we introduce a
polling
> >       * loop of 20 seconds for the server socket.  This introduces a
> >       * cost across platforms, but is necessary to maintain cross-
> platform
> >       * functionality.
> >       */
> >      private static int POLLING_INTERVAL = 20*1000;
> >
> >      /**
> >       * The server socket which this connection is managing
> >       */
> >      private ServerSocket serverSocket;
> >
> >      /**
> >       * The connection handler factory that generates connection
> >       * handlers to manage client connections to this server socket
> >       */
> >      private ConnectionHandlerFactory handlerFactory;
> >
> >      /**
> >       * The thread pool used to spawn individual threads used to
manage
> each
> >       * client connection.
> >       */
> >      private ThreadPool connThreadPool;
> >
> >      /**
> >       * The timeout for client sockets spawned off this connection.
> >       */
> >      private int socketTimeout;
> >
> >      /**
> >       * The maximum number of open client connections that this
server
> >       * connection will allow.
> >       */
> >      private int maxOpenConn;
> >
> >      /**
> >       * A collection of client connection runners.
> >       */
> >      private final ArrayList clientConnectionRunners = new
ArrayList();
> >
> >      /**
> >       * The current number of open client connections.
> >       */
> >       private int openConnections = 0;
> >
> >      /**
> >       * The thread used to manage this server connection.
> >       */
> >      private Thread serverConnectionThread;
> >
> >      /**
> >       * The sole constructor for a ServerConnection.
> >       *
> >       * @param serverSocket the ServerSocket associated with this
> ServerConnection
> >       * @param handlerFactory the factory that generates
> ConnectionHandlers for the client
> >       *                       connections spawned off this
> ServerConnection
> >       * @param threadPool the ThreadPool used to obtain handler
threads
> >       * @param timeout the client idle timeout for this
> ServerConnection's client connections
> >       * @param maxOpenConn the maximum number of open client
connections
> allowed for this
> >       *                    ServerConnection
> >       */
> >      public ServerConnection(ServerSocket serverSocket,
> >                              ConnectionHandlerFactory
handlerFactory,
> >                              ThreadPool threadPool,
> >                              int timeout,
> >                              int maxOpenConn) {
> >          this.serverSocket = serverSocket;
> >          this.handlerFactory = handlerFactory;
> >          connThreadPool = threadPool;
> >          socketTimeout = timeout;
> >          this.maxOpenConn = maxOpenConn;
> >      }
> >
> >      /**
> >       * The dispose operation is called by the owning
ConnectionManager
> >       * at the end of its lifecycle.  Cleans up the server
connection,
> forcing
> >       * everything to finish.
> >       */
> >      public void dispose() {
> >          if (getLogger().isDebugEnabled()) {
> >              getLogger().debug("Disposing server connection..." +
> this.toString());
> >          }
> >          synchronized( this ) {
> >              if( null != serverConnectionThread ) {
> >                  // Execution of this block means that the run()
method
> >                  // hasn't finished yet.  So we interrupt the thread
> >                  // to terminate run() and wait for the run() method
> >                  // to finish.  The notifyAll() at the end of run()
will
> >                  // wake this thread and allow dispose() to end.
> >                  Thread thread = serverConnectionThread;
> >                  serverConnectionThread = null;
> >                  thread.interrupt();
> >                  try {
> >                      serverSocket.close();
> >                  } catch (IOException ie) {
> >                      // Ignored - we're doing this to break out of
the
> >                      // accept.  This minimizes the time required to
> >                      // shutdown the server.  Unfortunately, this is
> >                      // not guaranteed to work on all platforms.
See
> >                      // the comments for POLLING_INTERVAL
> >                  }
> >                  try {
> >                      if (POLLING_INTERVAL > 0) {
> >                          wait(2L*POLLING_INTERVAL);
> >                      } else {
> >                          wait();
> >                      }
> >                  } catch (InterruptedException ie) {
> >                      // Expected - just complete dispose()
> >                  }
> >              }
> >          }
> >
> >          getLogger().debug("Closed server connection - cleaning up
> clients - " + this.toString());
> >
> >          synchronized (clientConnectionRunners) {
> >              Iterator runnerIterator =
> clientConnectionRunners.iterator();
> >              while( runnerIterator.hasNext() )
> >              {
> >                  ClientConnectionRunner runner =
> (ClientConnectionRunner)runnerIterator.next();
> >                  runner.dispose();
> >                  runner = null;
> >              }
> >              clientConnectionRunners.clear();
> >              openConnections = 0;
> >          }
> >
> >          getLogger().debug("Cleaned up clients - " +
this.toString());
> >
> >      }
> >
> >      /**
> >       * Adds a ClientConnectionRunner to the set managed by this
> ServerConnection object.
> >       *
> >       * @param clientConnectionRunner the ClientConnectionRunner to
be
> added
> >       */
> >      private void addClientConnectionRunner(ClientConnectionRunner
> clientConnectionRunner) {
> >          synchronized (clientConnectionRunners) {
> >              clientConnectionRunners.add(clientConnectionRunner);
> >              openConnections++;
> >          }
> >      }
> >
> >      /**
> >       * Removes a ClientConnectionRunner from the set managed by
this
> ServerConnection object.
> >       *
> >       * @param clientConnectionRunner the ClientConnectionRunner to
be
> removed
> >       */
> >      private void
removeClientConnectionRunner(ClientConnectionRunner
> clientConnectionRunner) {
> >          synchronized (clientConnectionRunners) {
> >              clientConnectionRunners.remove(clientConnectionRunner);
> >              openConnections--;
> >          }
> >      }
> >
> >      /**
> >       * Provides the body for the thread of execution for a
> ServerConnection.
> >       * Connections made to the server socket are passed to an
> appropriate,
> >       * newly created, ClientConnectionRunner
> >       */
> >      public void run() {
> >          serverConnectionThread = Thread.currentThread();
> >
> >          int ioExceptionCount = 0;
> >          try {
> >              serverSocket.setSoTimeout(POLLING_INTERVAL);
> >          } catch (SocketException se) {
> >              // Ignored - for the moment
> >          }
> >          while( null != serverConnectionThread &&
> !serverConnectionThread.isInterrupted() ) {
> >              try {
> >                  Socket clientSocket = null;
> >                  try {
> >                      clientSocket = serverSocket.accept();
> >                  } catch( InterruptedIOException iioe ) {
> >                      // This exception is expected upon
ServerConnection
> shutdown.
> >                      // See the POLLING_INTERVAL comment
> >                      continue;
> >                  } catch( IOException se ) {
> >                      if (ioExceptionCount > 0) {
> >                          getLogger().error( "Fatal exception while
> listening on server socket.  Terminating connection.", se );
> >                          break;
> >                      } else {
> >                          continue;
> >                      }
> >                  } catch( SecurityException se ) {
> >                      getLogger().error( "Fatal exception while
listening
> on server socket.  Terminating connection.", se );
> >                      break;
> >                  }
> >                  ClientConnectionRunner runner = null;
> >                  synchronized (clientConnectionRunners) {
> >                      if ((maxOpenConn > 0) && (openConnections >=
> maxOpenConn)) {
> >                          if (getLogger().isWarnEnabled()) {
> >                              getLogger().warn("Maximum number of
open
> connections exceeded - refusing connection.  Current number of
connections
> is " + openConnections);
> >                          }
> >                          try {
> >                              clientSocket.close();
> >                          } catch (IOException ignored) {
> >                              // We ignore this exception, as we
already
> have an error condition.
> >                          }
> >                          continue;
> >                      } else {
> >                          clientSocket.setSoTimeout(socketTimeout);
> >                          runner =
> >                              new
ClientConnectionRunner(clientSocket,
> handlerFactory);
> >                      }
> >                  }
> >                  setupLogger( runner );
> >                  connThreadPool.execute( runner );
> >              } catch( IOException ioe ) {
> >                  getLogger().error( "Exception accepting
connection",
> ioe );
> >              } catch( Exception e ) {
> >                  getLogger().error( "Exception executing client
> connection runner: " + e.getMessage() );
> >              }
> >          }
> >          synchronized( this ) {
> >              serverConnectionThread = null;
> >              notifyAll();
> >          }
> >      }
> >
> >      /**
> >       * An inner class to provide the actual body of the thread of
> execution
> >       * that occurs upon a client connection.
> >       *
> >       * @author Andrei Ivanov
> >       * @author Peter M. Goldstein <fa...@alum.mit.edu>
> >       */
> >      class ClientConnectionRunner extends AbstractLogEnabled
> >          implements Runnable, Component  {
> >
> >          /**
> >           * The Socket that this client connection is using for
> transport.
> >           */
> >          private Socket clientSocket;
> >
> >          /**
> >           * The thread of execution associated with this client
> connection.
> >           */
> >          private Thread clientSocketThread;
> >
> >          /**
> >           * The ConnectionHandlerFactory that generates a
> ConnectionHandler for
> >           * this client connection.
> >           */
> >          private ConnectionHandlerFactory
> clientConnectionHandlerFactory;
> >
> >          /**
> >           * The constructor for a ClientConnectionRunner.
> >           *
> >           * @param socket the client socket associated with this
> ClientConnectionRunner
> >           * @param handlerFactory the factory that generates
> ConnectionHandlers for this
> >           *                       connection
> >           */
> >          public ClientConnectionRunner(Socket socket,
> >                                        ConnectionHandlerFactory
> handlerFactory) {
> >              clientSocket = socket;
> >              clientConnectionHandlerFactory = handlerFactory;
> >          }
> >
> >          /**
> >           * The dispose operation that terminates the runner.
Should
> only be
> >           * called by the ServerConnection that owns the
> ClientConnectionRunner
> >           */
> >          public void dispose() {
> >              synchronized( this ) {
> >                  if (null != clientSocketThread) {
> >                      // Execution of this block means that the run()
> method
> >                      // hasn't finished yet.  So we interrupt the
thread
> >                      // to terminate run() and wait for the run()
method
> >                      // to finish.  The notifyAll() at the end of
run()
> will
> >                      // wake this thread and allow dispose() to end.
> >                      clientSocketThread.interrupt();
> >                      clientSocketThread = null;
> >                      try {
> >                          wait();
> >                      } catch (InterruptedException ie) {
> >                          // Expected - return from the method
> >                      }
> >                  }
> >              }
> >          }
> >
> >          /**
> >           * Provides the body for the thread of execution dealing
with a
> particular client
> >           * connection.  An appropriate ConnectionHandler is
created,
> applied, executed,
> >           * and released.
> >           */
> >          public void run() {
> >              ConnectionHandler handler = null;
> >              try {
> >                  clientSocketThread = Thread.currentThread();
> >
ServerConnection.this.addClientConnectionRunner(this);
> >
> >                  handler =
> clientConnectionHandlerFactory.createConnectionHandler();
> >                  String connectionString = null;
> >                  if( getLogger().isDebugEnabled() ) {
> >                      connectionString = getConnectionString();
> >                      String message = "Starting " +
connectionString;
> >                      getLogger().debug( message );
> >                  }
> >
> >                  handler.handleConnection(clientSocket);
> >
> >                  if( getLogger().isDebugEnabled() ) {
> >                      String message = "Ending " + connectionString;
> >                      getLogger().debug( message );
> >                  }
> >              } catch( Exception e ) {
> >                  getLogger().warn( "Error handling connection", e );
> >              } finally {
> >
> >                  // Close the underlying socket
> >                  try {
> >                      clientSocket.close();
> >                  } catch( IOException ioe ) {
> >                      getLogger().warn( "Error shutting down
connection",
> ioe );
> >                  }
> >
> >                  // Release the handler and kill the reference to
the
> handler factory
> >                  if (handler != null) {
> >
> clientConnectionHandlerFactory.releaseConnectionHandler( handler );
> >                      handler = null;
> >                  }
> >                  clientConnectionHandlerFactory = null;
> >
> >                  // Remove this runner from the list of active
> connections.
> >
> ServerConnection.this.removeClientConnectionRunner(this);
> >
> >                  // Null out the thread, notify other threads to
> encourage
> >                  // a context switch
> >                  synchronized( this ) {
> >                      clientSocketThread = null;
> >                      notifyAll();
> >                  }
> >              }
> >          }
> >
> >          /**
> >           * Helper method to return a formatted string with
connection
> transport information.
> >           *
> >           * @return a formatted string
> >           */
> >          private String getConnectionString() {
> >              if (clientSocket == null) {
> >                  return "invalid socket";
> >              }
> >              StringBuffer connectionBuffer
> >                  = new StringBuffer(256)
> >                      .append("connection on ")
> >
> .append(clientSocket.getLocalAddress().getHostAddress().toString())
> >                      .append(":")
> >                      .append(clientSocket.getLocalPort())
> >                      .append(" from ")
> >
> .append(clientSocket.getInetAddress().getHostAddress().toString())
> >                      .append(":")
> >                      .append(clientSocket.getPort());
> >              return connectionBuffer.toString();
> >          }
> >      }
> >  }
> >
> >
> >
> >
> >
> >  1.1                  jakarta-
>
james/src/java/org/apache/james/util/connection/SimpleConnectionManager.
ja
> va
> >
> >  Index: SimpleConnectionManager.java
> >  ===================================================================
> >  /*
> >   * Copyright (C) The Apache Software Foundation. All rights
reserved.
> >   *
> >   * This software is published under the terms of the Apache
Software
> License
> >   * version 1.1, a copy of which has been included with this
> distribution in
> >   * the LICENSE file.
> >   */
> >  package org.apache.james.util.connection;
> >
> >  import java.net.ServerSocket;
> >  import java.util.HashMap;
> >
> >  import org.apache.avalon.excalibur.thread.ThreadPool;
> >
> >  import
>
org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFacto
ry
> ;
> >  import
> org.apache.avalon.cornerstone.services.connection.ConnectionManager;
> >  import
org.apache.avalon.cornerstone.services.threads.ThreadManager;
> >  import org.apache.avalon.framework.component.ComponentException;
> >  import org.apache.avalon.framework.component.ComponentManager;
> >  import org.apache.avalon.framework.component.Composable;
> >  import org.apache.avalon.framework.configuration.Configurable;
> >  import org.apache.avalon.framework.configuration.Configuration;
> >  import
> org.apache.avalon.framework.configuration.ConfigurationException;
> >
> >  import org.apache.avalon.framework.activity.Disposable;
> >  import org.apache.avalon.framework.logger.AbstractLogEnabled;
> >
> >
> >  /**
> >   * An implementation of ConnectionManager that supports
configurable
> >   * idle timeouts and a configurable value for the maximum number of
> >   * client connections to a particular port.
> >   *
> >   * @author Andrei Ivanov
> >   * @author Peter M. Goldstein <fa...@alum.mit.edu>
> >   */
> >  public class SimpleConnectionManager extends AbstractLogEnabled
> >      implements ConnectionManager, Composable, Configurable,
Disposable
> {
> >
> >      /**
> >       * The default value for client socket idle timeouts.  The
> >       * Java default is 0, meaning no timeout.  That's dangerous
> >       * for a connection handler like this one, because it can
> >       * easily lead to consumption of network resources.  So we
> >       * allow users to configure the system to allow no timeout,
> >       * but if no timeout is specified in the configuration, we
> >       * use a timeout of 5 minutes.
> >       */
> >      private static final int DEFAULT_SOCKET_TIMEOUT = 5 * 60 *
1000;
> >
> >      /**
> >       * The default value for the maximum number of allowed client
> >       * connections.
> >       */
> >      private static final int DEFAULT_MAX_CONNECTIONS = 30;
> >
> >      /**
> >       * The map of connection name / server connections managed by
this
> connection
> >       * manager.
> >       */
> >      private final HashMap connectionMap = new HashMap();
> >
> >      /**
> >       * The idle timeout for the individual sockets spawed from the
> server socket.
> >       */
> >      protected int timeout = 0;
> >
> >      /**
> >       * The maximum number of client connections allowed per server
> connection.
> >       */
> >      protected int maxOpenConn = 0;
> >
> >      /**
> >       * The ThreadManager component that is used to provide a
default
> thread pool.
> >       */
> >      private ThreadManager threadManager;
> >
> >      /**
> >       * Whether the SimpleConnectionManager has been disposed.
> >       */
> >      private volatile boolean disposed = false;
> >
> >      /**
> >       * @see
>
org.apache.avalon.framework.configuration.Configurable#configure(Configu
ra
> tion)
> >       */
> >      public void configure(final Configuration configuration) throws
> ConfigurationException {
> >          timeout = configuration.getChild("idle-
> timeout").getValueAsInteger(DEFAULT_SOCKET_TIMEOUT);
> >          maxOpenConn = configuration.getChild("max-
> connections").getValueAsInteger(DEFAULT_MAX_CONNECTIONS);
> >
> >          if (timeout < 0) {
> >              StringBuffer exceptionBuffer =
> >                  new StringBuffer(128)
> >                      .append("Specified socket timeout value of ")
> >                      .append(timeout)
> >                      .append(" is not a legal value.");
> >              throw new
> ConfigurationException(exceptionBuffer.toString());
> >          }
> >
> >          if (maxOpenConn < 0) {
> >              StringBuffer exceptionBuffer =
> >                  new StringBuffer(128)
> >                      .append("Specified maximum number of open
> connections of ")
> >                      .append(maxOpenConn)
> >                      .append(" is not a legal value.");
> >              throw new
> ConfigurationException(exceptionBuffer.toString());
> >          }
> >
> >          if (getLogger().isDebugEnabled()) {
> >              getLogger().debug("Connection timeout is "
> >                               + (timeout == 0 ? "unlimited" :
> Long.toString(timeout)));
> >              getLogger().debug("The maximum number of simultaneously
> open connections is "
> >                               + (maxOpenConn == 0 ? "unlimited" :
> Integer.toString(maxOpenConn)));
> >          }
> >      }
> >
> >      /**
> >       * @see
>
org.apache.avalon.framework.component.Composable#compose(ComponentManage
r)
> >       */
> >      public void compose(ComponentManager componentManager)
> >          throws ComponentException {
> >          threadManager = (ThreadManager)componentManager.lookup(
> ThreadManager.ROLE );
> >      }
> >
> >      /**
> >       * Disconnects all the underlying ServerConnections
> >       */
> >      public void dispose() {
> >          disposed = true;
> >          if (getLogger().isDebugEnabled()) {
> >              getLogger().debug("Starting SimpleConnectionManager
> dispose...");
> >          }
> >          final String[] names =
> (String[])connectionMap.keySet().toArray( new String[ 0 ] );
> >          for( int i = 0; i < names.length; i++ ) {
> >              try {
> >                  if (getLogger().isDebugEnabled()) {
> >                      getLogger().debug("Disconnecting
ServerConnection "
> + names[i]);
> >                  }
> >                  disconnect( names[ i ], true);
> >              } catch( final Exception e ) {
> >                  getLogger().warn( "Error disconnecting " + names[ i
],
> e );
> >              }
> >          }
> >          if (getLogger().isDebugEnabled()) {
> >              getLogger().debug("Finishing SimpleConnectionManager
> dispose...");
> >          }
> >      }
> >
> >      /**
> >       * Start managing a connection.
> >       * Management involves accepting connections and farming them
out
> to threads
> >       * from pool to be handled.
> >       *
> >       * @param name the name of connection
> >       * @param socket the ServerSocket from which to
> >       * @param handlerFactory the factory from which to acquire
handlers
> >       * @param threadPool the thread pool to use
> >       * @exception Exception if an error occurs
> >       */
> >      public void connect( String name,
> >                           ServerSocket socket,
> >                           ConnectionHandlerFactory handlerFactory,
> >                           ThreadPool threadPool )
> >          throws Exception {
> >
> >          if (disposed) {
> >              throw new IllegalStateException("Connection manager has
> already been shutdown.");
> >          }
> >          if( null != connectionMap.get( name ) ) {
> >              throw new IllegalArgumentException( "Connection already
> exists with name " +
> >                                                  name );
> >          }
> >
> >          ServerConnection runner = new ServerConnection(socket,
> handlerFactory, threadPool, timeout, maxOpenConn);
> >          setupLogger( runner );
> >          connectionMap.put( name, runner );
> >          threadPool.execute(runner);
> >      }
> >
> >      /**
> >       * Start managing a connection.
> >       * This is similar to other connect method except that it uses
> default thread pool.
> >       *
> >       * @param name the name of connection
> >       * @param socket the ServerSocket from which to
> >       * @param handlerFactory the factory from which to acquire
handlers
> >       * @exception Exception if an error occurs
> >       */
> >      public void connect( String name,
> >                           ServerSocket socket,
> >                           ConnectionHandlerFactory handlerFactory )
> >          throws Exception
> >      {
> >          connect( name, socket, handlerFactory,
> threadManager.getDefaultThreadPool() );
> >      }
> >
> >
> >      /**
> >       * This shuts down all handlers and socket, waiting for each to
> gracefully shutdown.
> >       *
> >       * @param name the name of connection
> >       * @exception Exception if an error occurs
> >       */
> >      public void disconnect( final String name )
> >          throws Exception {
> >
> >          disconnect( name, false );
> >      }
> >
> >      /**
> >       * This shuts down a connection.
> >       * If tearDown is true then it will forcefully the connection
and
> try
> >       * to return as soon as possible. Otherwise it will behave the
same
> as
> >       * void disconnect( String name );
> >       *
> >       * @param name the name of connection
> >       * @param tearDown if true will forcefully tear down all
handlers
> >       * @exception Exception if an error occurs
> >       */
> >      public void disconnect( final String name, final boolean
tearDown )
> >          throws Exception {
> >
> >          ServerConnection connection =
> (ServerConnection)connectionMap.remove( name );
> >          if( null == connection ) {
> >              throw new IllegalArgumentException( "No such connection
> with name " +
> >                                                  name );
> >          }
> >
> >          // TODO: deal with tear down
> >          connection.dispose();
> >      }
> >
> >  }
> >
> >
> >
> >  1.1                  jakarta-
>
james/src/java/org/apache/james/util/connection/SimpleConnectionManager.
xi
> nfo
> >
> >  Index: SimpleConnectionManager.xinfo
> >  ===================================================================
> >  <?xml version="1.0"?>
> >
> >
> >  <blockinfo>
> >
> >    <!-- section to describe block -->
> >    <block>
> >      <name>SimpleConnectionManager</name>
> >      <version>1.0</version>
> >    </block>
> >
> >    <!-- services that are offered by this block -->
> >    <services>
> >      <service
>
name="org.apache.avalon.cornerstone.services.connection.ConnectionManage
r"
> />
> >    </services>
> >
> >    <!-- services that are required by this block -->
> >    <dependencies>
> >      <dependency>
> >        <service
> name="org.apache.avalon.cornerstone.services.threads.ThreadManager"/>
> >      </dependency>
> >   </dependencies>
> >
> >  </blockinfo>
> >
> >
> >
> >  1.1                  jakarta-
> james/src/java/org/apache/james/util/connection/package.html
> >
> >  Index: package.html
> >  ===================================================================
> >  <body>
> >  <p>Provides classes that implement Avalon Cornerstone connection
> services.  It would be desirable to have these classes eventually
moved to
> Cornerstone.</p>
> >  </body>
> >
> >
> >
> >
> >--
> >To unsubscribe, e-mail:   <mailto:james-dev-
> unsubscribe@jakarta.apache.org>
> >For additional commands, e-mail: <mailto:james-dev-
> help@jakarta.apache.org>
> >
> >
> >
> >




--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-james/src/java/org/apache/james/util/connection ServerConnection.java SimpleConnectionManager.java SimpleConnectionManager.xinfo package.html

Posted by Nathan Carter <na...@gmx.net>.
Peter,

Current HEAD compiles fine, but there's a parsing error at runtime due 
to a couple of typos in src/conf/james-config.xml - here is the patch.

Nathan Carter


pgoldstein@apache.org wrote:

>pgoldstein    2002/10/07 00:16:46
>
>  Modified:    src/conf james-assembly.xml james-config.xml
>  Added:       src/java/org/apache/james/util/connection
>                        ServerConnection.java SimpleConnectionManager.java
>                        SimpleConnectionManager.xinfo package.html
>  Log:
>  Added the SimpleConnectionManager and supporting class ServerConnection.
>  
>  Changed the configuration/assembly -
>    i) Replaced tabs with spaces
>    ii) Added comments
>    iii) Removed AuthService references
>    iv) Increased max number of threads in thread pool
>    v) Changed ConnectionManager to default to org.apache.james.util.connection.SimpleConnectionManager
>    vi) Added commented authRequired element to NNTP server
>  
>  Revision  Changes    Path
>  1.12      +1 -6      jakarta-james/src/conf/james-assembly.xml
>  
>  Index: james-assembly.xml
>  ===================================================================
>  RCS file: /home/cvs/jakarta-james/src/conf/james-assembly.xml,v
>  retrieving revision 1.11
>  retrieving revision 1.12
>  diff -u -r1.11 -r1.12
>  --- james-assembly.xml	2 Oct 2002 09:53:37 -0000	1.11
>  +++ james-assembly.xml	7 Oct 2002 07:16:46 -0000	1.12
>  @@ -99,11 +99,6 @@
>                role="org.apache.james.nntpserver.repository.NNTPRepository"/>
>     </block>
>   
>  -  <!-- NNTP Authentication Service -->
>  -  <block name="nntpauth" class="org.apache.james.nntpserver.AuthServiceImpl" >
>  -    <provide name="users-store" role="org.apache.james.services.UsersStore"/>
>  -  </block>
>  -
>     <!-- NNTP Repository -->
>     <block name="nntp-repository" class="org.apache.james.nntpserver.repository.NNTPRepositoryImpl" />
>   
>  @@ -142,7 +137,7 @@
>   
>     <!-- The Connection Manager block -->
>     <block name="connections"
>  -         class="org.apache.avalon.cornerstone.blocks.connection.DefaultConnectionManager" >
>  +         class="org.apache.james.util.connection.SimpleConnectionManager" >
>       <provide name="thread-manager"
>                role="org.apache.avalon.cornerstone.services.threads.ThreadManager" />
>     </block>
>  
>  
>  
>  1.34      +92 -49    jakarta-james/src/conf/james-config.xml
>  
>  Index: james-config.xml
>  ===================================================================
>  RCS file: /home/cvs/jakarta-james/src/conf/james-config.xml,v
>  retrieving revision 1.33
>  retrieving revision 1.34
>  diff -u -r1.33 -r1.34
>  --- james-config.xml	27 Sep 2002 16:31:06 -0000	1.33
>  +++ james-config.xml	7 Oct 2002 07:16:46 -0000	1.34
>  @@ -7,10 +7,10 @@
>                                  README!
>   
>   This configuration file is designed to run without alteration for simple tests.
>  -It assumes you have a DNS server on localhost and assigns a root pasword of root.
>  +It assumes you have a DNS server on localhost and assigns a root password of root.
>   
>   In case the defaults do not suit you, the items you are most likely to need to change
>  -are preceeded by a CHECKME! or CONFIRM? comment in the left margin.
>  +are preceded by a CHECKME! or CONFIRM? comment in the left margin.
>   
>   For production use you will probably need to make more extensive changes, see
>   http://jakarta.apache.org/james/configuration_v2_0.html
>  @@ -30,16 +30,16 @@
>              If autodetectIP is not FALSE, James will also allow add the IP address for each servername.
>              The automatic IP detection is to support RFC 2821, Sec 4.1.3, address literals.
>              By default, the servername 'localhost' is specified. This can be removed, if required. -->
>  -      <servernames autodetect="TRUE" autodetectIP="TRUE">
>  +      <servernames autodetect="true" autodetectIP="true">
>            <!--<servername>To override autodetected server names  uncomment this.  </servername> -->
>            <servername>localhost</servername>
>  -       	<!-- IMPORTANT if you are using fetchpop it is important to include the -->
>  -       	<!-- fetched domains here to prevent looping                            -->
>  +        <!-- IMPORTANT if you are using fetchpop it is important to include the -->
>  +        <!-- fetched domains here to prevent looping                            -->
>         </servernames>
>   
>         <!-- Set whether user names are case sensitive or case insensitive -->
>         <!-- Set whether to enable local aliases -->
>  -      <usernames ignoreCase="TRUE" enableAliases="TRUE" enableForwarding="TRUE"/>
>  +      <usernames ignoreCase="true" enableAliases="true" enableForwarding="true"/>
>   
>         <!-- The inbox repository is the location for users inboxes -->
>         <!-- Default setting: file based repository - enter path ( use  "file:///" for absolute) -->
>  @@ -62,22 +62,22 @@
>      <!-- fetched domains in the <servernames> section of the <James> block      -->
>      <!-- above. fetchpop is disabled by default.                                  -->
>      
>  -	<fetchpop enabled="false">
>  -		<!-- you can have as many fetch tasks as you want to        -->
>  -		<!-- but each must have a unique name to identify itself by -->
>  -		<fetch name="mydomain.com">
>  -			<!-- host name or IP address -->
>  -			<host>mail.mydomain.com</host>
>  -			<!-- acount login username -->
>  -			<user>username</user>
>  -			<!-- account login password -->
>  -			<password>pass</password>
>  -			<!-- Interval to check this account in milliseconds, 600000 is every ten minutes -->
>  -			<interval>600000</interval>
>  -		</fetch>
>  -	</fetchpop>
>  -	
>  -	
>  +    <fetchpop enabled="false">
>  +        <!-- you can have as many fetch tasks as you want to        -->
>  +        <!-- but each must have a unique name to identify itself by -->
>  +        <fetch name="mydomain.com">
>  +            <!-- host name or IP address -->
>  +            <host>mail.mydomain.com</host>
>  +            <!-- acount login username -->
>  +            <user>username</user>
>  +            <!-- account login password -->
>  +            <password>pass</password>
>  +            <!-- Interval to check this account in milliseconds, 600000 is every ten minutes -->
>  +            <interval>600000</interval>
>  +        </fetch>
>  +    </fetchpop>
>  +    
>  +    
>      <!-- The James Spool Manager block  -->
>      <spoolmanager>
>         <!-- number of spool threads -->
>  @@ -119,7 +119,7 @@
>            <!-- Sample matching to kill a message (send to Null) -->
>            <mailet match="RecipientIs=badboy@badhost" class="Null"/>
>   
>  -         <!-- Send remaining mails to the transport processor for either  local or remote delivery -->
>  +         <!-- Send remaining mails to the transport processor for either local or remote delivery -->
>            <mailet match="All" class="ToProcessor">
>               <processor> transport </processor>
>            </mailet>
>  @@ -142,7 +142,7 @@
>            <!--<mailet match="All" class="NotifyPostmaster"/>-->
>         </processor>
>   
>  -      <!--  Processor CONFIGURATION SAMPLE: transport is a sample custom  processor for local or remote delivery -->
>  +      <!--  Processor CONFIGURATION SAMPLE: transport is a sample custom processor for local or remote delivery -->
>         <processor name="transport">
>   
>            <!-- Is the recipient is for a local account, deliver it locally -->
>  @@ -153,7 +153,7 @@
>               <processor>error</processor>
>            </mailet>
>   
>  -		<!-- CHECKME!    Anti-relay mailet: Add your network address here,
>  +        <!-- CHECKME!    Anti-relay mailet: Add your network address here,
>                     e.g. "RemoteAddrNotInNetwork=127.0.0.1, abc.de.*, 192.168.0.*"-->
>   
>            <!-- This matcher-mailet pair can prevent relaying...
>  @@ -244,7 +244,7 @@
>                  autodetect is TRUE, James will attempt to discover its own name OR
>                  use 'localhost'. If autodetect is FALSE, James will use the value
>                  given OR 'localhost' -->
>  -         <helloName autodetect="TRUE">myMailServer</helloName>
>  +         <helloName autodetect="true">myMailServer</helloName>
>            <administrator_accounts>
>   <!-- CHECKME! Change the default password! -->
>   <!-- FILL ME!!!!!!  You must provide a password for your  administrator accounts (cannot be blank) -->
>  @@ -254,9 +254,9 @@
>         </handler>
>      </remotemanager>
>   
>  -	<!-- The POP3 server is enabled by default -->
>  -	<!-- Disabling blocks will stop them from listening, -->
>  -	<!-- but does not free as many resources as removing them would -->
>  +    <!-- The POP3 server is enabled by default -->
>  +    <!-- Disabling blocks will stop them from listening, -->
>  +    <!-- but does not free as many resources as removing them would -->
>      <pop3server enabled="true">
>         <!-- port 995 is the well-known/IANA registered port for POP3S  ie over SSL/TLS -->
>         <!-- port 100 is the well-known/IANA registered port for Standard POP3 -->
>  @@ -273,14 +273,14 @@
>                  autodetect is TRUE, James will attempt to discover its own name OR
>                  use 'localhost'. If autodetect is FALSE, James will use the value
>                  given OR 'localhost' -->
>  -         <helloName autodetect="TRUE">myMailServer</helloName>
>  +         <helloName autodetect="true">myMailServer</helloName>
>            <connectiontimeout>120000</connectiontimeout>
>         </handler>
>      </pop3server>
>   
>  -	<!-- The SMTP server is enabled by default -->
>  -	<!-- Disabling blocks will stop them from listening, -->
>  -	<!-- but does not free as many resources as removing them would -->
>  +    <!-- The SMTP server is enabled by default -->
>  +    <!-- Disabling blocks will stop them from listening, -->
>  +    <!-- but does not free as many resources as removing them would -->
>      <smtpserver enabled="true">
>         <port>25</port>
>   
>  @@ -295,7 +295,7 @@
>                autodetect is TRUE, James will attempt to discover its own name OR
>                use 'localhost'. If autodetect is FALSE, James will use the value
>                given OR 'localhost' -->
>  -         <helloName autodetect="TRUE">myMailServer</helloName>
>  +         <helloName autodetect="true">myMailServer</helloName>
>            <connectiontimeout>360000</connectiontimeout>
>            <!--  uncomment this if you want
>                  SMTP AUTH support. This is useful if you have users who need to use
>  @@ -313,9 +313,9 @@
>         </handler>
>      </smtpserver>
>      
>  -   	<!-- The NNTP server is enabled by default -->
>  -	<!-- Disabling blocks will stop them from listening, -->
>  -	<!-- but does not free as many resources as removing them would -->
>  +    <!-- The NNTP server is enabled by default -->
>  +    <!-- Disabling blocks will stop them from listening, -->
>  +    <!-- but does not free as many resources as removing them would -->
>      <nntpserver enabled="true">
>         <!-- port 563 is the well-known/IANA registered port for nntp over SSL/TLS -->
>         <!-- port 119 is the well-known/IANA registered port for Standard nntp -->
>  @@ -332,16 +332,13 @@
>               autodetect is TRUE, James will attempt to discover its own name OR
>               use 'localhost'. If autodetect is FALSE, James will use the value
>               given OR 'localhost' -->
>  -         <helloName autodetect="TRUE">myMailServer</helloName>
>  +         <helloName autodetect="true">myMailServer</helloName>
>            <connectiontimeout>120000</connectiontimeout>
>  +          <!-- Set the authRequired value to true to enable authenticated NNTP -->
>  +         <authRequired>false</authRequired>
>         </handler>
>      </nntpserver>
>   
>  -   <nntpauth>
>  -      <!-- make this true, if you want only authenticated users to access NNTP-->
>  -      <authRequired>false</authRequired>
>  -   </nntpauth>
>  -
>      <nntp-repository>
>         <!-- make this true to disallow posting to all newsgroups-->
>         <readOnly>false</readOnly>
>  @@ -460,8 +457,8 @@
>         User repositories are required for the following purposes:
>         - holding information about Users of the James mail server
>         - holding lists of users for the listserv mailet
>  -      Currently, 2 different storage options are available:
>  -      - file-based storage using Java serialisation
>  +      Currently, two different storage options are available:
>  +      - file-based storage using Java serialization
>         - database-backed storage
>         (Use of database or file-system is defined on a "per-repository" basis)
>         Note: Two user repositories are required for default configuration:
>  @@ -533,8 +530,19 @@
>         </data-sources>
>      </database-connections>
>   
>  -   <!-- Configuration for Cornerstone Blocks only after here NOTHING BELOW THIS SHOULD NEED CHANGING,
>  -    (unless you want secure sockets (TLS)) -->
>  +   <!-- Configuration for Cornerstone Services -->
>  +   <!-- -->
>  +   <!-- For a simple configuration, nothing beneath this line should require -->
>  +   <!-- alteration. -->
>  +   <!-- -->
>  +   <!-- You will need to adjust the Socket Manager service configuration if you want -->
>  +   <!-- to enable secure sockets (TLS) for any James service.                        -->
>  +   <!-- -->
>  +   <!-- Complex or high volume configurations may require changes to the parameters -->
>  +   <!-- in this section.  Please read the James and Avalon documentation before -->
>  +   <!-- attempting to adjust this section. -->
>  +   <!-- -->
>  +
>      <!-- The Storage block -->
>      <objectstorage>
>         <repositories>
>  @@ -566,7 +574,42 @@
>            </repository>
>         </repositories>
>      </objectstorage>
>  +   <!-- The Connection Manager block -->
>  +   <!-- -->
>  +   <!-- The idle-timeout is the number of milliseconds that it will take for idle -->
>  +   <!-- client connections managed by this connection manager to be marked at timed out. -->
>  +   <!-- If no value is specified, the value defaults to 5 minutes, 300000 milliseconds -->
>  +   <!-- A value of 0 means that client sockets will not timeout. -->
>  +   <!-- -->
>  +   <!-- The max-connections parameter specifies the maximum number of client connections -->
>  +   <!-- that this connection manager will allow per managed server socket. -->
>  +   <!-- If no value is specified, the value defaults to 30. -->
>  +   <!-- A value of 0 means that there is no limit imposed by the connection manager, although -->
>  +   <!-- resource limitations imposed by other components (i.e. max # of threads) may -->
>  +   <!-- serve to limit the number of open connections. -->
>  +   <!-- -->
>  +   <connections>
>  +      <idle-timeout>300000<idle-timeout>
>  +      <max-connections>30<max-connections>
>  +   </connections>
>      <!-- The Socket Manager block -->
>  +   <!-- -->
>  +   <!-- The server-sockets element has a number of factory sub-elements. -->
>  +   <!-- Each of the factory elements has a name and class attribute -->
>  +   <!-- The name attribute for each factory element must be unique.  -->
>  +   <!-- The class attribute is the name of a class that implements the -->
>  +   <!-- interface org.apache.avalon.cornerstone.services.ServerSocketFactory -->
>  +   <!-- Specific factory elements may require some sub-elements.  This is -->
>  +   <!-- factory class dependent. -->
>  +   <!-- -->
>  +   <!-- The client-sockets element has a number of factory sub-elements. -->
>  +   <!-- Each of the factory elements has a name and class attribute -->
>  +   <!-- The name attribute for each factory element must be unique.  -->
>  +   <!-- The class attribute is the name of a class that implements the -->
>  +   <!-- interface org.apache.avalon.cornerstone.services.SocketFactory -->
>  +   <!-- Specific factory elements may require some sub-elements.  This is -->
>  +   <!-- factory class dependent. -->
>  +   <!-- -->
>      <sockets>
>         <server-sockets>
>            <factory name="plain" class="org.apache.avalon.cornerstone.blocks.sockets.DefaultServerSocketFactory"/>
>  @@ -592,7 +635,7 @@
>            <priority>5</priority>
>            <!-- are threads daemon threads ? -->
>            <is-daemon>false</is-daemon>
>  -         <max-threads>40</max-threads>
>  +         <max-threads>100</max-threads>
>            <!-- these are ignored at the moment but will be fixed in later revisions -->
>            <min-threads>20</min-threads>
>            <min-spare-threads>20</min-spare-threads>
>  
>  
>  
>  1.1                  jakarta-james/src/java/org/apache/james/util/connection/ServerConnection.java
>  
>  Index: ServerConnection.java
>  ===================================================================
>  /*
>   * Copyright (C) The Apache Software Foundation. All rights reserved.
>   *
>   * This software is published under the terms of the Apache Software License
>   * version 1.1, a copy of which has been included with this distribution in
>   * the LICENSE.txt file.
>   */
>  package org.apache.james.util.connection;
>  
>  import java.io.IOException;
>  import java.io.InterruptedIOException;
>  import java.net.ServerSocket;
>  import java.net.Socket;
>  import java.net.SocketException;
>  import java.util.ArrayList;
>  import java.util.Iterator;
>  import java.util.List;
>  
>  import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
>  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
>  import org.apache.avalon.excalibur.thread.ThreadPool;
>  import org.apache.avalon.framework.component.Component;
>  import org.apache.avalon.framework.logger.AbstractLogEnabled;
>  
>  
>  /**
>   * Represents a single server socket managed by a connection manager.
>   * The connection manager will spawn a single ServerConnection for each
>   * server socket that the connection manager is managing.
>   *
>   * @author Andrei Ivanov
>   * @author Peter M. Goldstein <fa...@alum.mit.edu>
>   */
>  public class ServerConnection extends AbstractLogEnabled
>      implements Component, Runnable {
>  
>      /**
>       * This is a hack to deal with the fact that there appears to be
>       * no platform-independent way to break out of a ServerSocket
>       * accept() call.  On some platforms closing either the ServerSocket
>       * itself, or its associated InputStream, causes the accept 
>       * method to exit.  Unfortunately, this behavior is not consistent
>       * across platforms.  The deal with this, we introduce a polling
>       * loop of 20 seconds for the server socket.  This introduces a
>       * cost across platforms, but is necessary to maintain cross-platform
>       * functionality.
>       */
>      private static int POLLING_INTERVAL = 20*1000;
>  
>      /**
>       * The server socket which this connection is managing
>       */
>      private ServerSocket serverSocket;
>  
>      /**
>       * The connection handler factory that generates connection
>       * handlers to manage client connections to this server socket
>       */
>      private ConnectionHandlerFactory handlerFactory;
>  
>      /**
>       * The thread pool used to spawn individual threads used to manage each
>       * client connection.
>       */
>      private ThreadPool connThreadPool;
>  
>      /**
>       * The timeout for client sockets spawned off this connection.
>       */
>      private int socketTimeout;
>  
>      /**
>       * The maximum number of open client connections that this server
>       * connection will allow.
>       */
>      private int maxOpenConn;
>  
>      /**
>       * A collection of client connection runners.
>       */
>      private final ArrayList clientConnectionRunners = new ArrayList();    
>  
>      /**
>       * The current number of open client connections.
>       */
>       private int openConnections = 0;
>  
>      /**
>       * The thread used to manage this server connection.
>       */
>      private Thread serverConnectionThread;    
>  
>      /**
>       * The sole constructor for a ServerConnection.
>       *
>       * @param serverSocket the ServerSocket associated with this ServerConnection
>       * @param handlerFactory the factory that generates ConnectionHandlers for the client
>       *                       connections spawned off this ServerConnection
>       * @param threadPool the ThreadPool used to obtain handler threads
>       * @param timeout the client idle timeout for this ServerConnection's client connections
>       * @param maxOpenConn the maximum number of open client connections allowed for this
>       *                    ServerConnection
>       */
>      public ServerConnection(ServerSocket serverSocket,
>                              ConnectionHandlerFactory handlerFactory,
>                              ThreadPool threadPool,
>                              int timeout,
>                              int maxOpenConn) {
>          this.serverSocket = serverSocket;
>          this.handlerFactory = handlerFactory;
>          connThreadPool = threadPool;
>          socketTimeout = timeout;
>          this.maxOpenConn = maxOpenConn;
>      }
>  
>      /**
>       * The dispose operation is called by the owning ConnectionManager 
>       * at the end of its lifecycle.  Cleans up the server connection, forcing
>       * everything to finish.
>       */
>      public void dispose() {
>          if (getLogger().isDebugEnabled()) {
>              getLogger().debug("Disposing server connection..." + this.toString());
>          }
>          synchronized( this ) {
>              if( null != serverConnectionThread ) {
>                  // Execution of this block means that the run() method
>                  // hasn't finished yet.  So we interrupt the thread
>                  // to terminate run() and wait for the run() method
>                  // to finish.  The notifyAll() at the end of run() will
>                  // wake this thread and allow dispose() to end.
>                  Thread thread = serverConnectionThread;
>                  serverConnectionThread = null;
>                  thread.interrupt();
>                  try {
>                      serverSocket.close();
>                  } catch (IOException ie) {
>                      // Ignored - we're doing this to break out of the 
>                      // accept.  This minimizes the time required to
>                      // shutdown the server.  Unfortunately, this is
>                      // not guaranteed to work on all platforms.  See
>                      // the comments for POLLING_INTERVAL
>                  }
>                  try {
>                      if (POLLING_INTERVAL > 0) {
>                          wait(2L*POLLING_INTERVAL);
>                      } else {
>                          wait();
>                      }
>                  } catch (InterruptedException ie) {
>                      // Expected - just complete dispose()
>                  }
>              }
>          }
>  
>          getLogger().debug("Closed server connection - cleaning up clients - " + this.toString());
>  
>          synchronized (clientConnectionRunners) {
>              Iterator runnerIterator = clientConnectionRunners.iterator();
>              while( runnerIterator.hasNext() )
>              {
>                  ClientConnectionRunner runner = (ClientConnectionRunner)runnerIterator.next();
>                  runner.dispose();
>                  runner = null;
>              }
>              clientConnectionRunners.clear();
>              openConnections = 0;
>          }
>  
>          getLogger().debug("Cleaned up clients - " + this.toString());
>  
>      }
>  
>      /**
>       * Adds a ClientConnectionRunner to the set managed by this ServerConnection object.
>       *
>       * @param clientConnectionRunner the ClientConnectionRunner to be added
>       */
>      private void addClientConnectionRunner(ClientConnectionRunner clientConnectionRunner) {
>          synchronized (clientConnectionRunners) {
>              clientConnectionRunners.add(clientConnectionRunner);
>              openConnections++;
>          }
>      }
>  
>      /**
>       * Removes a ClientConnectionRunner from the set managed by this ServerConnection object.
>       *
>       * @param clientConnectionRunner the ClientConnectionRunner to be removed
>       */
>      private void removeClientConnectionRunner(ClientConnectionRunner clientConnectionRunner) {
>          synchronized (clientConnectionRunners) {
>              clientConnectionRunners.remove(clientConnectionRunner);
>              openConnections--;
>          }
>      }
>  
>      /**
>       * Provides the body for the thread of execution for a ServerConnection.
>       * Connections made to the server socket are passed to an appropriate,
>       * newly created, ClientConnectionRunner
>       */
>      public void run() {
>          serverConnectionThread = Thread.currentThread();
>  
>          int ioExceptionCount = 0;
>          try {
>              serverSocket.setSoTimeout(POLLING_INTERVAL);
>          } catch (SocketException se) {
>              // Ignored - for the moment
>          }
>          while( null != serverConnectionThread && !serverConnectionThread.isInterrupted() ) {
>              try {
>                  Socket clientSocket = null;
>                  try {
>                      clientSocket = serverSocket.accept();
>                  } catch( InterruptedIOException iioe ) {
>                      // This exception is expected upon ServerConnection shutdown.
>                      // See the POLLING_INTERVAL comment
>                      continue;
>                  } catch( IOException se ) {
>                      if (ioExceptionCount > 0) {
>                          getLogger().error( "Fatal exception while listening on server socket.  Terminating connection.", se );
>                          break;
>                      } else {
>                          continue;
>                      }
>                  } catch( SecurityException se ) {
>                      getLogger().error( "Fatal exception while listening on server socket.  Terminating connection.", se );
>                      break;
>                  }
>                  ClientConnectionRunner runner = null;
>                  synchronized (clientConnectionRunners) {
>                      if ((maxOpenConn > 0) && (openConnections >= maxOpenConn)) {
>                          if (getLogger().isWarnEnabled()) {
>                              getLogger().warn("Maximum number of open connections exceeded - refusing connection.  Current number of connections is " + openConnections);
>                          }
>                          try {
>                              clientSocket.close();
>                          } catch (IOException ignored) {
>                              // We ignore this exception, as we already have an error condition.
>                          }
>                          continue;
>                      } else {
>                          clientSocket.setSoTimeout(socketTimeout);
>                          runner =
>                              new ClientConnectionRunner(clientSocket, handlerFactory);
>                      }
>                  }
>                  setupLogger( runner );
>                  connThreadPool.execute( runner );
>              } catch( IOException ioe ) {
>                  getLogger().error( "Exception accepting connection", ioe );
>              } catch( Exception e ) {
>                  getLogger().error( "Exception executing client connection runner: " + e.getMessage() );
>              }
>          }
>          synchronized( this ) {
>              serverConnectionThread = null;
>              notifyAll();
>          }
>      }
>  
>      /**
>       * An inner class to provide the actual body of the thread of execution
>       * that occurs upon a client connection.
>       *
>       * @author Andrei Ivanov
>       * @author Peter M. Goldstein <fa...@alum.mit.edu>
>       */
>      class ClientConnectionRunner extends AbstractLogEnabled
>          implements Runnable, Component  {
>  
>          /**
>           * The Socket that this client connection is using for transport.
>           */
>          private Socket clientSocket;
>  
>          /**
>           * The thread of execution associated with this client connection.
>           */
>          private Thread clientSocketThread;
>  
>          /**
>           * The ConnectionHandlerFactory that generates a ConnectionHandler for
>           * this client connection.
>           */
>          private ConnectionHandlerFactory clientConnectionHandlerFactory;
>        
>          /**
>           * The constructor for a ClientConnectionRunner.
>           *
>           * @param socket the client socket associated with this ClientConnectionRunner
>           * @param handlerFactory the factory that generates ConnectionHandlers for this
>           *                       connection
>           */
>          public ClientConnectionRunner(Socket socket,
>                                        ConnectionHandlerFactory handlerFactory) {
>              clientSocket = socket;
>              clientConnectionHandlerFactory = handlerFactory;
>          }
>        
>          /**
>           * The dispose operation that terminates the runner.  Should only be
>           * called by the ServerConnection that owns the ClientConnectionRunner
>           */
>          public void dispose() {
>              synchronized( this ) {
>                  if (null != clientSocketThread) {
>                      // Execution of this block means that the run() method
>                      // hasn't finished yet.  So we interrupt the thread
>                      // to terminate run() and wait for the run() method
>                      // to finish.  The notifyAll() at the end of run() will
>                      // wake this thread and allow dispose() to end.
>                      clientSocketThread.interrupt();
>                      clientSocketThread = null;
>                      try {
>                          wait();
>                      } catch (InterruptedException ie) {
>                          // Expected - return from the method
>                      }
>                  }
>              }
>          }
>  
>          /**
>           * Provides the body for the thread of execution dealing with a particular client
>           * connection.  An appropriate ConnectionHandler is created, applied, executed, 
>           * and released. 
>           */
>          public void run() {
>              ConnectionHandler handler = null;
>              try {
>                  clientSocketThread = Thread.currentThread();
>                  ServerConnection.this.addClientConnectionRunner(this);
>  
>                  handler = clientConnectionHandlerFactory.createConnectionHandler();
>                  String connectionString = null;
>                  if( getLogger().isDebugEnabled() ) {
>                      connectionString = getConnectionString();
>                      String message = "Starting " + connectionString;
>                      getLogger().debug( message );
>                  }
>  
>                  handler.handleConnection(clientSocket);
>  
>                  if( getLogger().isDebugEnabled() ) {
>                      String message = "Ending " + connectionString;
>                      getLogger().debug( message );
>                  }
>              } catch( Exception e ) {
>                  getLogger().warn( "Error handling connection", e );
>              } finally {
>      
>                  // Close the underlying socket
>                  try {
>                      clientSocket.close();
>                  } catch( IOException ioe ) {
>                      getLogger().warn( "Error shutting down connection", ioe );
>                  }
>      
>                  // Release the handler and kill the reference to the handler factory
>                  if (handler != null) {
>                      clientConnectionHandlerFactory.releaseConnectionHandler( handler );
>                      handler = null;
>                  }
>                  clientConnectionHandlerFactory = null;
>  
>                  // Remove this runner from the list of active connections.
>                  ServerConnection.this.removeClientConnectionRunner(this);
>  
>                  // Null out the thread, notify other threads to encourage
>                  // a context switch
>                  synchronized( this ) {
>                      clientSocketThread = null;
>                      notifyAll();
>                  }
>              }
>          }
>  
>          /**
>           * Helper method to return a formatted string with connection transport information.
>           *
>           * @return a formatted string
>           */
>          private String getConnectionString() {
>              if (clientSocket == null) {
>                  return "invalid socket";
>              }
>              StringBuffer connectionBuffer
>                  = new StringBuffer(256)
>                      .append("connection on ")
>                      .append(clientSocket.getLocalAddress().getHostAddress().toString())
>                      .append(":")
>                      .append(clientSocket.getLocalPort())
>                      .append(" from ")
>                      .append(clientSocket.getInetAddress().getHostAddress().toString())
>                      .append(":")
>                      .append(clientSocket.getPort());
>              return connectionBuffer.toString();
>          }
>      }
>  }
>  
>  
>  
>  
>  
>  1.1                  jakarta-james/src/java/org/apache/james/util/connection/SimpleConnectionManager.java
>  
>  Index: SimpleConnectionManager.java
>  ===================================================================
>  /*
>   * Copyright (C) The Apache Software Foundation. All rights reserved.
>   *
>   * This software is published under the terms of the Apache Software License
>   * version 1.1, a copy of which has been included with this distribution in
>   * the LICENSE file.
>   */
>  package org.apache.james.util.connection;
>  
>  import java.net.ServerSocket;
>  import java.util.HashMap;
>  
>  import org.apache.avalon.excalibur.thread.ThreadPool;
>  
>  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
>  import org.apache.avalon.cornerstone.services.connection.ConnectionManager;
>  import org.apache.avalon.cornerstone.services.threads.ThreadManager;
>  import org.apache.avalon.framework.component.ComponentException;
>  import org.apache.avalon.framework.component.ComponentManager;
>  import org.apache.avalon.framework.component.Composable;
>  import org.apache.avalon.framework.configuration.Configurable;
>  import org.apache.avalon.framework.configuration.Configuration;
>  import org.apache.avalon.framework.configuration.ConfigurationException;
>  
>  import org.apache.avalon.framework.activity.Disposable;
>  import org.apache.avalon.framework.logger.AbstractLogEnabled;
>  
>  
>  /**
>   * An implementation of ConnectionManager that supports configurable
>   * idle timeouts and a configurable value for the maximum number of 
>   * client connections to a particular port.
>   *
>   * @author Andrei Ivanov
>   * @author Peter M. Goldstein <fa...@alum.mit.edu>
>   */
>  public class SimpleConnectionManager extends AbstractLogEnabled
>      implements ConnectionManager, Composable, Configurable, Disposable {
>  
>      /**
>       * The default value for client socket idle timeouts.  The
>       * Java default is 0, meaning no timeout.  That's dangerous
>       * for a connection handler like this one, because it can
>       * easily lead to consumption of network resources.  So we
>       * allow users to configure the system to allow no timeout,
>       * but if no timeout is specified in the configuration, we
>       * use a timeout of 5 minutes.
>       */
>      private static final int DEFAULT_SOCKET_TIMEOUT = 5 * 60 * 1000;
>  
>      /**
>       * The default value for the maximum number of allowed client
>       * connections.
>       */
>      private static final int DEFAULT_MAX_CONNECTIONS = 30;
>  
>      /**
>       * The map of connection name / server connections managed by this connection
>       * manager.
>       */
>      private final HashMap connectionMap = new HashMap();
>    
>      /**
>       * The idle timeout for the individual sockets spawed from the server socket.
>       */
>      protected int timeout = 0;
>  
>      /**
>       * The maximum number of client connections allowed per server connection.
>       */
>      protected int maxOpenConn = 0;
>  
>      /**
>       * The ThreadManager component that is used to provide a default thread pool.
>       */
>      private ThreadManager threadManager;
>  
>      /**
>       * Whether the SimpleConnectionManager has been disposed.
>       */
>      private volatile boolean disposed = false;
>  
>      /**
>       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
>       */
>      public void configure(final Configuration configuration) throws ConfigurationException {
>          timeout = configuration.getChild("idle-timeout").getValueAsInteger(DEFAULT_SOCKET_TIMEOUT);
>          maxOpenConn = configuration.getChild("max-connections").getValueAsInteger(DEFAULT_MAX_CONNECTIONS);
>  
>          if (timeout < 0) {
>              StringBuffer exceptionBuffer =
>                  new StringBuffer(128)
>                      .append("Specified socket timeout value of ")
>                      .append(timeout)
>                      .append(" is not a legal value.");
>              throw new ConfigurationException(exceptionBuffer.toString());
>          } 
>  
>          if (maxOpenConn < 0) {
>              StringBuffer exceptionBuffer =
>                  new StringBuffer(128)
>                      .append("Specified maximum number of open connections of ")
>                      .append(maxOpenConn)
>                      .append(" is not a legal value.");
>              throw new ConfigurationException(exceptionBuffer.toString());
>          } 
>  
>          if (getLogger().isDebugEnabled()) {
>              getLogger().debug("Connection timeout is " 
>                               + (timeout == 0 ? "unlimited" : Long.toString(timeout)));
>              getLogger().debug("The maximum number of simultaneously open connections is " 
>                               + (maxOpenConn == 0 ? "unlimited" : Integer.toString(maxOpenConn)));
>          }
>      }
>  
>      /**
>       * @see org.apache.avalon.framework.component.Composable#compose(ComponentManager)
>       */
>      public void compose(ComponentManager componentManager) 
>          throws ComponentException {
>          threadManager = (ThreadManager)componentManager.lookup( ThreadManager.ROLE );
>      }
>  
>      /**
>       * Disconnects all the underlying ServerConnections
>       */
>      public void dispose() {
>          disposed = true;
>          if (getLogger().isDebugEnabled()) {
>              getLogger().debug("Starting SimpleConnectionManager dispose...");
>          }
>          final String[] names = (String[])connectionMap.keySet().toArray( new String[ 0 ] );
>          for( int i = 0; i < names.length; i++ ) {
>              try {
>                  if (getLogger().isDebugEnabled()) {
>                      getLogger().debug("Disconnecting ServerConnection " + names[i]);
>                  }
>                  disconnect( names[ i ], true);
>              } catch( final Exception e ) {
>                  getLogger().warn( "Error disconnecting " + names[ i ], e );
>              }
>          }
>          if (getLogger().isDebugEnabled()) {
>              getLogger().debug("Finishing SimpleConnectionManager dispose...");
>          }
>      }
>    
>      /**
>       * Start managing a connection.
>       * Management involves accepting connections and farming them out to threads
>       * from pool to be handled.
>       *
>       * @param name the name of connection
>       * @param socket the ServerSocket from which to
>       * @param handlerFactory the factory from which to acquire handlers
>       * @param threadPool the thread pool to use
>       * @exception Exception if an error occurs
>       */
>      public void connect( String name,
>                           ServerSocket socket,
>                           ConnectionHandlerFactory handlerFactory,
>                           ThreadPool threadPool )
>          throws Exception {
>  
>          if (disposed) {
>              throw new IllegalStateException("Connection manager has already been shutdown.");
>          }
>          if( null != connectionMap.get( name ) ) {
>              throw new IllegalArgumentException( "Connection already exists with name " +
>                                                  name );
>          }
>      
>          ServerConnection runner = new ServerConnection(socket, handlerFactory, threadPool, timeout, maxOpenConn);
>          setupLogger( runner );
>          connectionMap.put( name, runner );
>          threadPool.execute(runner);
>      }
>  
>      /**
>       * Start managing a connection.
>       * This is similar to other connect method except that it uses default thread pool.
>       *
>       * @param name the name of connection
>       * @param socket the ServerSocket from which to
>       * @param handlerFactory the factory from which to acquire handlers
>       * @exception Exception if an error occurs
>       */
>      public void connect( String name,
>                           ServerSocket socket,
>                           ConnectionHandlerFactory handlerFactory )
>          throws Exception
>      {
>          connect( name, socket, handlerFactory, threadManager.getDefaultThreadPool() );
>      }
>  
>    
>      /**
>       * This shuts down all handlers and socket, waiting for each to gracefully shutdown.
>       *
>       * @param name the name of connection
>       * @exception Exception if an error occurs
>       */
>      public void disconnect( final String name )
>          throws Exception {
>  
>          disconnect( name, false );
>      }
>    
>      /**
>       * This shuts down a connection.
>       * If tearDown is true then it will forcefully the connection and try
>       * to return as soon as possible. Otherwise it will behave the same as
>       * void disconnect( String name );
>       *
>       * @param name the name of connection
>       * @param tearDown if true will forcefully tear down all handlers
>       * @exception Exception if an error occurs
>       */
>      public void disconnect( final String name, final boolean tearDown )
>          throws Exception {
>  
>          ServerConnection connection = (ServerConnection)connectionMap.remove( name );
>          if( null == connection ) {
>              throw new IllegalArgumentException( "No such connection with name " +
>                                                  name );
>          }
>  
>          // TODO: deal with tear down
>          connection.dispose();
>      }
>    
>  }
>  
>  
>  
>  1.1                  jakarta-james/src/java/org/apache/james/util/connection/SimpleConnectionManager.xinfo
>  
>  Index: SimpleConnectionManager.xinfo
>  ===================================================================
>  <?xml version="1.0"?>
>  
>  
>  <blockinfo>
>  
>    <!-- section to describe block -->
>    <block>
>      <name>SimpleConnectionManager</name>
>      <version>1.0</version>
>    </block>
>  
>    <!-- services that are offered by this block -->
>    <services>
>      <service name="org.apache.avalon.cornerstone.services.connection.ConnectionManager"/>
>    </services>
>  
>    <!-- services that are required by this block -->
>    <dependencies>
>      <dependency>
>        <service name="org.apache.avalon.cornerstone.services.threads.ThreadManager"/>
>      </dependency>
>   </dependencies>
>  
>  </blockinfo>
>  
>  
>  
>  1.1                  jakarta-james/src/java/org/apache/james/util/connection/package.html
>  
>  Index: package.html
>  ===================================================================
>  <body>
>  <p>Provides classes that implement Avalon Cornerstone connection services.  It would be desirable to have these classes eventually moved to Cornerstone.</p>
>  </body>
>  
>  
>  
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>
>
>
>  
>