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