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 rd...@apache.org on 2009/08/11 21:26:47 UTC
svn commit: r803252 - in /james/server/sandbox/container:
avalon-socket-library/src/main/java/org/apache/james/socket/
nntpserver-function/src/main/java/org/apache/james/nntpserver/
pop3server-function/src/main/java/org/apache/james/pop3server/ remotem...
Author: rdonkin
Date: Tue Aug 11 19:26:47 2009
New Revision: 803252
URL: http://svn.apache.org/viewvc?rev=803252&view=rev
Log:
Simplified by pushing down abstract super class inherited only by one class
Removed:
james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java
Modified:
james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java
james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java
james/server/sandbox/container/nntpserver-function/src/main/java/org/apache/james/nntpserver/NNTPHandler.java
james/server/sandbox/container/pop3server-function/src/main/java/org/apache/james/pop3server/POP3Handler.java
james/server/sandbox/container/remotemanager-function/src/main/java/org/apache/james/remotemanager/RemoteManagerHandler.java
Modified: james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java?rev=803252&r1=803251&r2=803252&view=diff
==============================================================================
--- james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java (original)
+++ james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java Tue Aug 11 19:26:47 2009
@@ -677,7 +677,7 @@
*/
protected ConnectionHandler newHandler()
throws Exception {
- AbstractJamesHandler theHandler = (AbstractJamesHandler)theHandlerPool.get();
+ DelegatingJamesHandler theHandler = (DelegatingJamesHandler)theHandlerPool.get();
if (getLogger().isDebugEnabled()) {
getLogger().debug("Handler [" + theHandler + "] obtained from pool.");
@@ -796,7 +796,7 @@
* @see org.apache.avalon.excalibur.pool.ObjectFactory#newInstance()
*/
public Object newInstance() throws Exception {
- final AbstractJamesHandler delegatingJamesHandler = new DelegatingJamesHandler(newProtocolHandlerInstance());
+ final DelegatingJamesHandler delegatingJamesHandler = new DelegatingJamesHandler(newProtocolHandlerInstance());
delegatingJamesHandler.setName("Handler-" + handlerCount.getAndAdd(1));
return delegatingJamesHandler;
}
Modified: james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java?rev=803252&r1=803251&r2=803252&view=diff
==============================================================================
--- james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java (original)
+++ james/server/sandbox/container/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java Tue Aug 11 19:26:47 2009
@@ -19,19 +19,35 @@
package org.apache.james.socket;
+import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
+import org.apache.avalon.excalibur.pool.Poolable;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.api.dnsservice.DNSService;
+import org.apache.james.util.InternetPrintWriter;
import org.apache.james.util.watchdog.Watchdog;
+import org.apache.james.util.watchdog.WatchdogTarget;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
+import java.net.SocketException;
/**
* Common Handler code
*/
-public class DelegatingJamesHandler extends AbstractJamesHandler implements ProtocolHandlerHelper {
+public class DelegatingJamesHandler extends AbstractLogEnabled implements ProtocolHandlerHelper, ConnectionHandler, Poolable,Serviceable {
protected ProtocolHandler protocolHandler;
@@ -41,6 +57,426 @@
this.protocolHandler.setProtocolHandlerHelper(this);
}
+
+ private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
+
+ private static final int DEFAULT_INPUT_BUFFER_SIZE = 1024;
+
+ /** Name used by default */
+ private static final String DEFAULT_NAME = "Handler-ANON";
+
+ /**
+ * The thread executing this handler
+ */
+ private Thread handlerThread;
+
+ /**
+ * The TCP/IP socket over which the service interaction
+ * is occurring
+ */
+ protected Socket socket;
+
+ /**
+ * The writer to which outgoing messages are written.
+ */
+ protected PrintWriter out;
+
+ /**
+ * The incoming stream of bytes coming from the socket.
+ */
+ protected InputStream in;
+
+ /**
+ * The reader associated with incoming characters.
+ */
+ protected CRLFTerminatedReader inReader;
+
+ /**
+ * The socket's output stream
+ */
+ protected OutputStream outs;
+
+ /**
+ * The watchdog being used by this handler to deal with idle timeouts.
+ */
+ protected Watchdog theWatchdog;
+
+ /**
+ * The watchdog target that idles out this handler.
+ */
+ private WatchdogTarget theWatchdogTarget = new JamesWatchdogTarget();
+
+ /**
+ * The remote host name obtained by lookup on the socket.
+ */
+ private String remoteHost = null;
+
+ /**
+ * The remote IP address of the socket.
+ */
+ private String remoteIP = null;
+
+ /**
+ * The DNSService
+ */
+ private DNSService dnsServer = null;
+
+ /**
+ * Used for debug: if not null enable tcp stream dump.
+ */
+ private String tcplogprefix = null;
+
+ /**
+ * Names the handler.
+ * This name is used for contextual logging.
+ */
+ private String name = DEFAULT_NAME;
+
+
+ /**
+ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+ */
+ public void service(ServiceManager arg0) throws ServiceException {
+ setDnsServer((DNSService) arg0.lookup(DNSService.ROLE));
+ }
+
+ /**
+ * Helper method for accepting connections.
+ * This MUST be called in the specializations.
+ *
+ * @param connection The Socket which belongs to the connection
+ * @throws IOException get thrown if an IO error is detected
+ */
+ protected void initHandler( Socket connection ) throws IOException {
+ this.socket = connection;
+ remoteIP = socket.getInetAddress().getHostAddress();
+ remoteHost = dnsServer.getHostName(socket.getInetAddress());
+
+ try {
+ synchronized (this) {
+ handlerThread = Thread.currentThread();
+ }
+ in = new BufferedInputStream(socket.getInputStream(), DEFAULT_INPUT_BUFFER_SIZE);
+ outs = new BufferedOutputStream(socket.getOutputStream(), DEFAULT_OUTPUT_BUFFER_SIZE);
+ // enable tcp dump for debug
+ if (tcplogprefix != null) {
+ outs = new SplitOutputStream(outs, new FileOutputStream(tcplogprefix+"out"));
+ in = new CopyInputStream(in, new FileOutputStream(tcplogprefix+"in"));
+ }
+
+ // An ASCII encoding can be used because all transmissions other
+ // that those in the message body command are guaranteed
+ // to be ASCII
+ inReader = new CRLFTerminatedReader(in, "ASCII");
+
+ out = new InternetPrintWriter(outs, true);
+ } catch (RuntimeException e) {
+ StringBuffer exceptionBuffer =
+ new StringBuffer(256)
+ .append("[" + toString() + "] Unexpected exception opening from ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append("): ")
+ .append(e.getMessage());
+ String exceptionString = exceptionBuffer.toString();
+ getLogger().error(exceptionString, e);
+ throw e;
+ } catch (IOException e) {
+ StringBuffer exceptionBuffer =
+ new StringBuffer(256)
+ .append("[" + toString() + "] Cannot open connection from ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append("): ")
+ .append(e.getMessage());
+ String exceptionString = exceptionBuffer.toString();
+ getLogger().error(exceptionString, e);
+ throw e;
+ }
+
+ if (getLogger().isInfoEnabled()) {
+ StringBuffer infoBuffer =
+ new StringBuffer(128)
+ .append("[" + toString() + "]Connection from ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(")");
+ getLogger().info(infoBuffer.toString());
+ }
+ }
+
+ /**
+ * The method clean up and close the allocated resources
+ */
+ private void cleanHandler() {
+ // Clear the Watchdog
+ if (theWatchdog != null) {
+ ContainerUtil.dispose(theWatchdog);
+ theWatchdog = null;
+ }
+
+ // Clear the streams
+ try {
+ if (inReader != null) {
+ inReader.close();
+ }
+ } catch (IOException ioe) {
+ getLogger().warn("[" + toString() + "] Unexpected exception occurred while closing reader: " + ioe);
+ } finally {
+ inReader = null;
+ }
+
+ in = null;
+
+ if (out != null) {
+ out.close();
+ out = null;
+ }
+ outs = null;
+
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException ioe) {
+ getLogger().warn("[" + toString() + "] Unexpected exception occurred while closing socket: " + ioe);
+ } finally {
+ socket = null;
+ }
+
+ remoteIP = null;
+ remoteHost = null;
+
+ synchronized (this) {
+ handlerThread = null;
+ }
+ }
+
+ /**
+ * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(java.net.Socket)
+ */
+ public void handleConnection(Socket connection) throws IOException {
+ initHandler(connection);
+
+ final Logger logger = getLogger();
+ try {
+
+ // Do something:
+ handleProtocol();
+
+ logger.debug("[" + toString() + "] Closing socket");
+ } catch (SocketException se) {
+ // Indicates a problem at the underlying protocol level
+ if (logger.isWarnEnabled()) {
+ String message =
+ new StringBuffer(64)
+ .append("[" + toString() + "]Socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append("): ")
+ .append(se.getMessage()).toString();
+ logger.warn(message);
+ logger.debug(se.getMessage(), se);
+ }
+ } catch ( InterruptedIOException iioe ) {
+ if (logger.isErrorEnabled()) {
+ StringBuffer errorBuffer =
+ new StringBuffer(64)
+ .append("[" + toString() + "] Socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") timeout.");
+ logger.error( errorBuffer.toString(), iioe );
+ }
+ } catch ( IOException ioe ) {
+ if (logger.isWarnEnabled()) {
+ String message =
+ new StringBuffer(256)
+ .append("[" + toString() + "] Exception handling socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") : ")
+ .append(ioe.getMessage()).toString();
+ logger.warn(message);
+ logger.debug( ioe.getMessage(), ioe );
+ }
+ } catch (RuntimeException e) {
+ errorHandler(e);
+ } finally {
+ //Clear all the session state variables
+ cleanHandler();
+ resetHandler();
+ }
+ }
+
+ /**
+ * Set the Watchdog for use by this handler.
+ *
+ * @param theWatchdog the watchdog
+ */
+ public void setWatchdog(Watchdog theWatchdog) {
+ this.theWatchdog = theWatchdog;
+ }
+
+ /**
+ * Gets the Watchdog Target that should be used by Watchdogs managing
+ * this connection.
+ *
+ * @return the WatchdogTarget
+ */
+ WatchdogTarget getWatchdogTarget() {
+ return theWatchdogTarget;
+ }
+
+ /**
+ * Idle out this connection
+ */
+ void idleClose() {
+ if (getLogger() != null) {
+ getLogger().error("[" + toString() + "] Service Connection has idled out.");
+ }
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (Exception e) {
+ // ignored
+ } finally {
+ socket = null;
+ }
+
+ synchronized (this) {
+ // Interrupt the thread to recover from internal hangs
+ if (handlerThread != null) {
+ handlerThread.interrupt();
+ handlerThread = null;
+ }
+ }
+
+ }
+
+ /**
+ * This method logs at a "DEBUG" level the response string that
+ * was sent to the service client. The method is provided largely
+ * as syntactic sugar to neaten up the code base. It is declared
+ * private and final to encourage compiler inlining.
+ *
+ * @param responseString the response string sent to the client
+ */
+ private final void logResponseString(String responseString) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("[" + toString() + "] Sent: " + responseString);
+ }
+ }
+
+ /**
+ * Write and flush a response string. The response is also logged.
+ * Should be used for the last line of a multi-line response or
+ * for a single line response.
+ *
+ * @param responseString the response string sent to the client
+ */
+ public final void writeLoggedFlushedResponse(String responseString) {
+ out.println(responseString);
+ out.flush();
+ logResponseString(responseString);
+ }
+
+ /**
+ * Write a response string. The response is also logged.
+ * Used for multi-line responses.
+ *
+ * @param responseString the response string sent to the client
+ */
+ public final void writeLoggedResponse(String responseString) {
+ out.println(responseString);
+ logResponseString(responseString);
+ }
+
+ /**
+ * A private inner class which serves as an adaptor
+ * between the WatchdogTarget interface and this
+ * handler class.
+ */
+ private class JamesWatchdogTarget
+ implements WatchdogTarget {
+
+ /**
+ * @see org.apache.james.util.watchdog.WatchdogTarget#execute()
+ */
+ public void execute() {
+ DelegatingJamesHandler.this.idleClose();
+ }
+
+ /**
+ * Used for context sensitive logging
+ */
+ @Override
+ public String toString() {
+ return DelegatingJamesHandler.this.toString();
+ }
+ }
+
+ /**
+ * If not null, this will enable dump to file for tcp connections
+ *
+ * @param streamDumpDir the dir
+ */
+ public void setStreamDumpDir(String streamDumpDir) {
+ if (streamDumpDir != null) {
+ String streamdumpDir=streamDumpDir;
+ this.tcplogprefix = streamdumpDir+"/" + getName() + "_TCP-DUMP."+System.currentTimeMillis()+".";
+ File logdir = new File(streamdumpDir);
+ if (!logdir.exists()) {
+ logdir.mkdir();
+ }
+ } else {
+ this.tcplogprefix = null;
+ }
+ }
+
+ public void setDnsServer(DNSService dnsServer) {
+ this.dnsServer = dnsServer;
+ }
+
+ /**
+ * The name of this handler.
+ * Used for context sensitive logging.
+ * @return the name, not null
+ */
+ public final String getName() {
+ return name;
+ }
+
+ /**
+ * The name of this handler.
+ * Note that this name should be file-system safe.
+ * Used for context sensitive logging.
+ * @param name the name to set
+ */
+ public final void setName(final String name) {
+ if (name == null) {
+ this.name = DEFAULT_NAME;
+ } else {
+ this.name = name;
+ }
+ }
+
+ /**
+ * Use for context sensitive logging.
+ * @return the name of the handler
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
/**
* This method will be implemented checking for the correct class
* type.
@@ -80,7 +516,10 @@
* @see org.apache.james.socket.ProtocolHandlerHelper#defaultErrorHandler(java.lang.RuntimeException)
*/
public void defaultErrorHandler(RuntimeException e) {
- super.errorHandler(e);
+ if (getLogger().isErrorEnabled()) {
+ getLogger().error( "[" + toString() + "] Unexpected runtime exception: "
+ + e.getMessage(), e );
+ }
}
/**
Modified: james/server/sandbox/container/nntpserver-function/src/main/java/org/apache/james/nntpserver/NNTPHandler.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/container/nntpserver-function/src/main/java/org/apache/james/nntpserver/NNTPHandler.java?rev=803252&r1=803251&r2=803252&view=diff
==============================================================================
--- james/server/sandbox/container/nntpserver-function/src/main/java/org/apache/james/nntpserver/NNTPHandler.java (original)
+++ james/server/sandbox/container/nntpserver-function/src/main/java/org/apache/james/nntpserver/NNTPHandler.java Tue Aug 11 19:26:47 2009
@@ -252,7 +252,7 @@
boolean isAlreadyAuthenticated = false;
/**
- * @see org.apache.james.socket.AbstractJamesHandler#setConfigurationData(Object)
+ * @see ProtocolHandler#setConfigurationData(Object)
*/
public void setConfigurationData(Object theData) {
if (theData instanceof NNTPHandlerConfigurationData) {
@@ -263,7 +263,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#handleProtocol()
+ * @see ProtocolHandler#handleProtocol()
*/
public void handleProtocol() throws IOException {
// section 7.1
@@ -293,7 +293,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#errorHandler(java.lang.RuntimeException)
+ * @see ProtocolHandler#errorHandler(java.lang.RuntimeException)
*/
public void errorHandler(RuntimeException e) {
helper.defaultErrorHandler(e);
@@ -309,7 +309,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#resetHandler
+ * @see ProtocolHandler#resetHandler
*/
public void resetHandler() {
// Clear the selected group, article info
Modified: james/server/sandbox/container/pop3server-function/src/main/java/org/apache/james/pop3server/POP3Handler.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/container/pop3server-function/src/main/java/org/apache/james/pop3server/POP3Handler.java?rev=803252&r1=803251&r2=803252&view=diff
==============================================================================
--- james/server/sandbox/container/pop3server-function/src/main/java/org/apache/james/pop3server/POP3Handler.java (original)
+++ james/server/sandbox/container/pop3server-function/src/main/java/org/apache/james/pop3server/POP3Handler.java Tue Aug 11 19:26:47 2009
@@ -169,7 +169,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#handleProtocol()
+ * @see ProtocolHandler#handleProtocol()
*/
public void handleProtocol() throws IOException {
handlerState = AUTHENTICATION_READY;
@@ -266,7 +266,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#errorHandler(java.lang.RuntimeException)
+ * @see ProtocolHandler#errorHandler(java.lang.RuntimeException)
*/
public void errorHandler(RuntimeException e) {
helper.defaultErrorHandler(e);
Modified: james/server/sandbox/container/remotemanager-function/src/main/java/org/apache/james/remotemanager/RemoteManagerHandler.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/container/remotemanager-function/src/main/java/org/apache/james/remotemanager/RemoteManagerHandler.java?rev=803252&r1=803251&r2=803252&view=diff
==============================================================================
--- james/server/sandbox/container/remotemanager-function/src/main/java/org/apache/james/remotemanager/RemoteManagerHandler.java (original)
+++ james/server/sandbox/container/remotemanager-function/src/main/java/org/apache/james/remotemanager/RemoteManagerHandler.java Tue Aug 11 19:26:47 2009
@@ -205,7 +205,7 @@
}
/**
- * @see org.apache.james.socket.AbstractJamesHandler#errorHandler(java.lang.RuntimeException)
+ * @see ProtocolHandler#errorHandler(java.lang.RuntimeException)
*/
public void errorHandler(RuntimeException e) {
helper.getOutputWriter().println("Unexpected Error: "+e.getMessage());
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org