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 <[EMAIL PROTECTED]>
*/
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 <[EMAIL PROTECTED]>
*/
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 <[EMAIL PROTECTED]>
*/
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: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>