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 ba...@apache.org on 2006/05/08 00:36:12 UTC
svn commit: r404864 - in /james/server/trunk/src/java/org/apache/james:
core/AbstractJamesHandler.java nntpserver/NNTPHandler.java
pop3server/POP3Handler.java remotemanager/RemoteManagerHandler.java
smtpserver/SMTPHandler.java
Author: bago
Date: Sun May 7 15:36:08 2006
New Revision: 404864
URL: http://svn.apache.org/viewcvs?rev=404864&view=rev
Log:
Further generalization in protocol handling. Now the 4 specific protocol handler are Avalon free (all the avalon stuff is in the AbstractJamesHandler) and they share most of the low-level protocol code.
Please note that RemoteManagerHandler now uses the CRLFInputStreamReader so it now mandate a CRLF based communication.
Modified:
james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java
james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java
james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java
Modified: james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java?rev=404864&r1=404863&r2=404864&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java (original)
+++ james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java Sun May 7 15:36:08 2006
@@ -19,12 +19,22 @@
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.james.util.CRLFTerminatedReader;
+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.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
@@ -49,6 +59,21 @@
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;
@@ -58,8 +83,199 @@
*/
private WatchdogTarget theWatchdogTarget = new JamesWatchdogTarget();
-
+ /**
+ * This method will be implemented checking for the correct class
+ * type.
+ *
+ * @param theData Configuration Bean.
+ */
public abstract void setConfigurationData(Object theData);
+
+
+ /**
+ * The remote host name obtained by lookup on the socket.
+ */
+ protected String remoteHost = null;
+
+ /**
+ * The remote IP address of the socket.
+ */
+ protected String remoteIP = null;
+
+ /**
+ * Helper method for accepting connections.
+ * This MUST be called in the specializations.
+ */
+ protected void initHandler( Socket connection ) throws IOException {
+ this.socket = connection;
+ remoteIP = socket.getInetAddress().getHostAddress();
+ remoteHost = socket.getInetAddress().getHostName();
+ try {
+ synchronized (this) {
+ handlerThread = Thread.currentThread();
+ }
+ in = new BufferedInputStream(socket.getInputStream(), 1024);
+ // 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");
+ outs = new BufferedOutputStream(socket.getOutputStream(), 1024);
+ out = new InternetPrintWriter(outs, true);
+ } catch (RuntimeException e) {
+ StringBuffer exceptionBuffer =
+ new StringBuffer(256)
+ .append("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("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("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("Handler: 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("Handler: 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);
+
+ try {
+
+ // Do something:
+ handleProtocol();
+
+ getLogger().debug("Closing socket.");
+ } catch (SocketException se) {
+ if (getLogger().isErrorEnabled()) {
+ StringBuffer errorBuffer =
+ new StringBuffer(64)
+ .append("Socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") closed remotely.");
+ getLogger().error(errorBuffer.toString(), se );
+ }
+ } catch ( InterruptedIOException iioe ) {
+ if (getLogger().isErrorEnabled()) {
+ StringBuffer errorBuffer =
+ new StringBuffer(64)
+ .append("Socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") timeout.");
+ getLogger().error( errorBuffer.toString(), iioe );
+ }
+ } catch ( IOException ioe ) {
+ if (getLogger().isErrorEnabled()) {
+ StringBuffer errorBuffer =
+ new StringBuffer(256)
+ .append("Exception handling socket to ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") : ")
+ .append(ioe.getMessage());
+ getLogger().error( errorBuffer.toString(), ioe );
+ }
+ } catch (RuntimeException e) {
+ errorHandler(e);
+ } finally {
+ //Clear all the session state variables
+ cleanHandler();
+ resetHandler();
+ }
+ }
+
+ /**
+ * @param e
+ */
+ protected void errorHandler(RuntimeException e) {
+ if (getLogger().isErrorEnabled()) {
+ getLogger().error( "Unexpected runtime exception: "
+ + e.getMessage(), e );
+ }
+ }
+
+
+ protected abstract void handleProtocol() throws IOException;
+
+
+ protected abstract void resetHandler();
/**
@@ -163,6 +379,5 @@
}
}
-
}
Modified: james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java?rev=404864&r1=404863&r2=404864&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java (original)
+++ james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java Sun May 7 15:36:08 2006
@@ -17,7 +17,6 @@
package org.apache.james.nntpserver;
-import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.james.core.AbstractJamesHandler;
import org.apache.james.core.MailHeaders;
import org.apache.james.nntpserver.repository.NNTPArticle;
@@ -25,23 +24,16 @@
import org.apache.james.util.CharTerminatedInputStream;
import org.apache.james.util.DotStuffingInputStream;
import org.apache.james.util.ExtraDotOutputStream;
-import org.apache.james.util.InternetPrintWriter;
import org.apache.mailet.dates.RFC2980DateFormat;
import org.apache.mailet.dates.RFC977DateFormat;
import org.apache.mailet.dates.SimplifiedDateFormat;
import javax.mail.MessagingException;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
import java.io.SequenceInputStream;
-import java.net.Socket;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -222,31 +214,6 @@
private final static char[] NNTPTerminator = { '\r', '\n', '.', '\r', '\n' };
/**
- * The remote host name obtained by lookup on the socket.
- */
- private String remoteHost;
-
- /**
- * The remote IP address of the socket.
- */
- private String remoteIP;
-
- /**
- * The incoming stream of bytes coming from the socket.
- */
- private InputStream in;
-
- /**
- * The reader associated with incoming characters.
- */
- private BufferedReader reader;
-
- /**
- * The socket's output stream
- */
- private OutputStream outs;
-
- /**
* The current newsgroup.
*/
private NNTPGroup group;
@@ -292,123 +259,52 @@
}
/**
- * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket)
+ * @see org.apache.james.core.AbstractJamesHandler#handleProtocol()
*/
- public void handleConnection( Socket connection ) throws IOException {
- try {
- this.socket = connection;
- synchronized (this) {
- handlerThread = Thread.currentThread();
- }
- remoteIP = socket.getInetAddress().getHostAddress();
- remoteHost = socket.getInetAddress().getHostName();
- in = new BufferedInputStream(socket.getInputStream(), 1024);
- // An ASCII encoding can be used because all transmissions other
- // that those in the message body command are guaranteed
- // to be ASCII
- reader = new BufferedReader(new InputStreamReader(in, "ASCII"), 512);
- outs = new BufferedOutputStream(socket.getOutputStream(), 1024);
- out = new InternetPrintWriter(outs, true);
- } catch (Exception e) {
- StringBuffer exceptionBuffer =
- new StringBuffer(256)
- .append("Cannot open connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append("): ")
- .append(e.getMessage());
- String exceptionString = exceptionBuffer.toString();
- getLogger().error(exceptionString, e );
+ protected void handleProtocol() throws IOException {
+ // section 7.1
+ if ( theConfigData.getNNTPRepository().isReadOnly() ) {
+ StringBuffer respBuffer =
+ new StringBuffer(128)
+ .append("201 ")
+ .append(theConfigData.getHelloName())
+ .append(" NNTP Service Ready, posting prohibited");
+ writeLoggedFlushedResponse(respBuffer.toString());
+ } else {
+ StringBuffer respBuffer =
+ new StringBuffer(128)
+ .append("200 ")
+ .append(theConfigData.getHelloName())
+ .append(" NNTP Service Ready, posting permitted");
+ writeLoggedFlushedResponse(respBuffer.toString());
}
- try {
- // section 7.1
- if ( theConfigData.getNNTPRepository().isReadOnly() ) {
- StringBuffer respBuffer =
- new StringBuffer(128)
- .append("201 ")
- .append(theConfigData.getHelloName())
- .append(" NNTP Service Ready, posting prohibited");
- writeLoggedFlushedResponse(respBuffer.toString());
- } else {
- StringBuffer respBuffer =
- new StringBuffer(128)
- .append("200 ")
- .append(theConfigData.getHelloName())
- .append(" NNTP Service Ready, posting permitted");
- writeLoggedFlushedResponse(respBuffer.toString());
- }
-
- theWatchdog.start();
- while (parseCommand(reader.readLine())) {
- theWatchdog.reset();
- }
- theWatchdog.stop();
-
- getLogger().info("Connection closed");
- } catch (Exception e) {
- // If the connection has been idled out, the
- // socket will be closed and null. Do NOT
- // log the exception or attempt to send the
- // closing connection message
- if (socket != null) {
- try {
- doQUIT(null);
- } catch (Throwable t) {}
- getLogger().error( "Exception during connection:" + e.getMessage(), e );
- }
- } finally {
- resetHandler();
+ theWatchdog.start();
+ while (parseCommand(inReader.readLine())) {
+ theWatchdog.reset();
+ }
+ theWatchdog.stop();
+
+ getLogger().info("Connection closed");
+ }
+
+ protected void errorHandler(RuntimeException e) {
+ super.errorHandler(e);
+ // If the connection has been idled out, the
+ // socket will be closed and null. Do NOT
+ // log the exception or attempt to send the
+ // closing connection message
+ if (socket != null) {
+ try {
+ doQUIT(null);
+ } catch (Throwable t) {}
}
}
/**
* Resets the handler data to a basic state.
*/
- private void resetHandler() {
-
- // Clear the Watchdog
- if (theWatchdog != null) {
- ContainerUtil.dispose(theWatchdog);
- theWatchdog = null;
- }
-
- // Clear the streams
- try {
- if (reader != null) {
- reader.close();
- }
- } catch (IOException ioe) {
- getLogger().warn("NNTPHandler: Unexpected exception occurred while closing reader: " + ioe);
- } finally {
- reader = null;
- }
-
- in = null;
-
- if (out != null) {
- out.close();
- out = null;
- }
- outs = null;
-
- remoteHost = null;
- remoteIP = null;
- try {
- if (socket != null) {
- socket.close();
- }
- } catch (IOException ioe) {
- getLogger().warn("NNTPHandler: Unexpected exception occurred while closing socket: " + ioe);
- } finally {
- socket = null;
- }
-
- synchronized (this) {
- handlerThread = null;
- }
-
+ protected void resetHandler() {
// Clear the selected group, article info
group = null;
currentArticleNumber = -1;
Modified: james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java?rev=404864&r1=404863&r2=404864&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java (original)
+++ james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java Sun May 7 15:36:08 2006
@@ -17,7 +17,6 @@
package org.apache.james.pop3server;
-import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.commons.collections.ListUtils;
import org.apache.james.Constants;
import org.apache.james.core.AbstractJamesHandler;
@@ -25,20 +24,16 @@
import org.apache.james.services.MailRepository;
import org.apache.james.util.CRLFTerminatedReader;
import org.apache.james.util.ExtraDotOutputStream;
-import org.apache.james.util.InternetPrintWriter;
import org.apache.james.util.watchdog.BytesWrittenResetOutputStream;
import org.apache.mailet.Mail;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
@@ -96,16 +91,6 @@
private MailRepository userInbox;
/**
- * The reader associated with incoming characters.
- */
- private CRLFTerminatedReader in;
-
- /**
- * The socket's output stream
- */
- private OutputStream outs;
-
- /**
* The current transaction state of the handler
*/
private int state;
@@ -140,155 +125,58 @@
}
/**
- * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket)
+ * @see org.apache.james.core.AbstractJamesHandler#handleProtocol()
*/
- public void handleConnection( Socket connection )
- throws IOException {
-
- String remoteHost = "";
- String remoteIP = "";
-
- try {
- this.socket = connection;
- synchronized (this) {
- handlerThread = Thread.currentThread();
- }
- // in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"), 512);
- in = new CRLFTerminatedReader(new BufferedInputStream(socket.getInputStream(), 512), "ASCII");
- remoteIP = socket.getInetAddress().getHostAddress ();
- remoteHost = socket.getInetAddress().getHostName ();
- } catch (Exception e) {
- if (getLogger().isErrorEnabled()) {
- StringBuffer exceptionBuffer =
- new StringBuffer(256)
- .append("Cannot open connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append("): ")
- .append(e.getMessage());
- getLogger().error( exceptionBuffer.toString(), e );
- }
+ protected void handleProtocol() throws IOException {
+ state = AUTHENTICATION_READY;
+ user = "unknown";
+ StringBuffer responseBuffer =
+ new StringBuffer(256)
+ .append(OK_RESPONSE)
+ .append(" ")
+ .append(theConfigData.getHelloName())
+ .append(" POP3 server (")
+ .append(POP3Handler.softwaretype)
+ .append(") ready ");
+ out.println(responseBuffer.toString());
+ out.flush();
+
+ theWatchdog.start();
+ while (parseCommand(readCommandLine())) {
+ theWatchdog.reset();
}
-
+ theWatchdog.stop();
if (getLogger().isInfoEnabled()) {
StringBuffer logBuffer =
new StringBuffer(128)
- .append("Connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") ");
+ .append("Connection for ")
+ .append(user)
+ .append(" from ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append(") closed.");
getLogger().info(logBuffer.toString());
}
-
+ }
+
+ /**
+ * @see org.apache.james.core.AbstractJamesHandler#errorHandler(java.lang.RuntimeException)
+ */
+ protected void errorHandler(RuntimeException e) {
+ super.errorHandler(e);
try {
- outs = new BufferedOutputStream(socket.getOutputStream(), 1024);
- out = new InternetPrintWriter(outs, true);
- state = AUTHENTICATION_READY;
- user = "unknown";
- StringBuffer responseBuffer =
- new StringBuffer(256)
- .append(OK_RESPONSE)
- .append(" ")
- .append(theConfigData.getHelloName())
- .append(" POP3 server (")
- .append(POP3Handler.softwaretype)
- .append(") ready ");
- out.println(responseBuffer.toString());
- out.flush();
-
- theWatchdog.start();
- while (parseCommand(readCommandLine())) {
- theWatchdog.reset();
- }
- theWatchdog.stop();
- if (getLogger().isInfoEnabled()) {
- StringBuffer logBuffer =
- new StringBuffer(128)
- .append("Connection for ")
- .append(user)
- .append(" from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") closed.");
- getLogger().info(logBuffer.toString());
- }
- } catch (Exception e) {
out.println(ERR_RESPONSE + " Error closing connection.");
out.flush();
- StringBuffer exceptionBuffer =
- new StringBuffer(128)
- .append("Exception during connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") : ")
- .append(e.getMessage());
- getLogger().error(exceptionBuffer.toString(), e );
- } finally {
- resetHandler();
+ } catch (Throwable t) {
+
}
}
/**
* Resets the handler data to a basic state.
*/
- private void resetHandler() {
-
- if (theWatchdog != null) {
- ContainerUtil.dispose(theWatchdog);
- theWatchdog = null;
- }
-
- // Close and clear streams, sockets
-
- try {
- if (socket != null) {
- socket.close();
- socket = null;
- }
- } catch (IOException ioe) {
- // Ignoring exception on close
- } finally {
- socket = null;
- }
-
- try {
- if (in != null) {
- in.close();
- }
- } catch (Exception e) {
- // Ignored
- } finally {
- in = null;
- }
-
- try {
- if (out != null) {
- out.close();
- }
- } catch (Exception e) {
- // Ignored
- } finally {
- out = null;
- }
-
- try {
- if (outs != null) {
- outs.close();
- }
- } catch (Exception e) {
- // Ignored
- } finally {
- outs = null;
- }
-
- synchronized (this) {
- handlerThread = null;
- }
-
+ protected void resetHandler() {
// Clear user data
user = null;
userInbox = null;
@@ -346,7 +234,7 @@
*/
final String readCommandLine() throws IOException {
for (;;) try {
- String commandLine = in.readLine();
+ String commandLine = inReader.readLine();
if (commandLine != null) {
commandLine = commandLine.trim();
}
@@ -1020,5 +908,6 @@
private void doUnknownCmd(String command,String argument,String argument1) {
writeLoggedFlushedResponse(ERR_RESPONSE);
}
+
}
Modified: james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java?rev=404864&r1=404863&r2=404864&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java (original)
+++ james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java Sun May 7 15:36:08 2006
@@ -17,7 +17,6 @@
package org.apache.james.remotemanager;
-import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.james.Constants;
import org.apache.james.core.AbstractJamesHandler;
import org.apache.james.services.JamesUser;
@@ -28,12 +27,7 @@
import javax.mail.internet.ParseException;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
import java.net.Socket;
import java.util.Iterator;
import java.util.Locale;
@@ -141,11 +135,6 @@
private UsersRepository users;
/**
- * The reader associated with incoming commands.
- */
- private BufferedReader in;
-
- /**
* Set the configuration data for the handler.
*
* @param theData the configuration data
@@ -164,133 +153,86 @@
/**
* @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket)
*/
- public void handleConnection( final Socket connection )
- throws IOException {
-
- socket = connection;
- String remoteIP = socket.getInetAddress().getHostAddress();
- String remoteHost = socket.getInetAddress().getHostName();
-
- synchronized (this) {
- handlerThread = Thread.currentThread();
+ protected void handleProtocol() throws IOException {
+ writeLoggedResponse("JAMES Remote Administration Tool " + Constants.SOFTWARE_VERSION );
+ writeLoggedResponse("Please enter your login and password");
+ String login = null;
+ String password = null;
+ do {
+ if (login != null) {
+ final String message = "Login failed for " + login;
+ writeLoggedFlushedResponse(message);
+ }
+ writeLoggedFlushedResponse("Login id:");
+ login = inReader.readLine().trim();
+ writeLoggedFlushedResponse("Password:");
+ password = inReader.readLine().trim();
+ } while (!password.equals(theConfigData.getAdministrativeAccountData().get(login)) || password.length() == 0);
+
+ StringBuffer messageBuffer =
+ new StringBuffer(64)
+ .append("Welcome ")
+ .append(login)
+ .append(". HELP for a list of commands");
+ out.println( messageBuffer.toString() );
+ out.flush();
+ if (getLogger().isInfoEnabled()) {
+ StringBuffer infoBuffer =
+ new StringBuffer(128)
+ .append("Login for ")
+ .append(login)
+ .append(" successful");
+ getLogger().info(infoBuffer.toString());
}
try {
- in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ASCII"), 512);
- out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()), 512), false);
- if (getLogger().isInfoEnabled()) {
- StringBuffer infoBuffer =
- new StringBuffer(128)
- .append("Access from ")
- .append(remoteHost)
- .append("(")
- .append(remoteIP)
- .append(")");
- getLogger().info( infoBuffer.toString() );
- }
- writeLoggedResponse("JAMES Remote Administration Tool " + Constants.SOFTWARE_VERSION );
- writeLoggedResponse("Please enter your login and password");
- String login = null;
- String password = null;
- do {
- if (login != null) {
- final String message = "Login failed for " + login;
- writeLoggedFlushedResponse(message);
- }
- writeLoggedFlushedResponse("Login id:");
- login = in.readLine().trim();
- writeLoggedFlushedResponse("Password:");
- password = in.readLine().trim();
- } while (!password.equals(theConfigData.getAdministrativeAccountData().get(login)) || password.length() == 0);
-
- StringBuffer messageBuffer =
- new StringBuffer(64)
- .append("Welcome ")
- .append(login)
- .append(". HELP for a list of commands");
- out.println( messageBuffer.toString() );
+ out.print(theConfigData.getPrompt());
out.flush();
- if (getLogger().isInfoEnabled()) {
- StringBuffer infoBuffer =
- new StringBuffer(128)
- .append("Login for ")
- .append(login)
- .append(" successful");
- getLogger().info(infoBuffer.toString());
- }
-
- try {
+ theWatchdog.start();
+ while (parseCommand(inReader.readLine())) {
+ theWatchdog.reset();
out.print(theConfigData.getPrompt());
out.flush();
- theWatchdog.start();
- while (parseCommand(in.readLine())) {
- theWatchdog.reset();
- out.print(theConfigData.getPrompt());
- out.flush();
- }
- theWatchdog.stop();
- } catch (IOException ioe) {
- //We can cleanly ignore this as it's probably a socket timeout
- } catch (Throwable thr) {
- System.out.println("Exception: " + thr.getMessage());
- getLogger().error("Encountered exception in handling the remote manager connection.", thr);
}
- StringBuffer infoBuffer =
- new StringBuffer(64)
- .append("Logout for ")
- .append(login)
- .append(".");
- getLogger().info(infoBuffer.toString());
+ theWatchdog.stop();
+ } catch (IOException ioe) {
+ //We can cleanly ignore this as it's probably a socket timeout
+ } catch (Throwable thr) {
+ System.out.println("Exception: " + thr.getMessage());
+ getLogger().error("Encountered exception in handling the remote manager connection.", thr);
+ }
+ StringBuffer infoBuffer =
+ new StringBuffer(64)
+ .append("Logout for ")
+ .append(login)
+ .append(".");
+ getLogger().info(infoBuffer.toString());
- } catch ( final IOException e ) {
- out.println("Error. Closing connection");
- out.flush();
- if (getLogger().isErrorEnabled()) {
- StringBuffer exceptionBuffer =
- new StringBuffer(128)
- .append("Exception during connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append("): ")
- .append(e.getMessage());
- getLogger().error(exceptionBuffer.toString());
- }
- } finally {
- resetHandler();
+ }
+
+ /**
+ * @see org.apache.james.core.AbstractJamesHandler#errorHandler(java.lang.RuntimeException)
+ */
+ protected void errorHandler(RuntimeException e) {
+ out.println("Unexpected Error: "+e.getMessage());
+ out.flush();
+ if (getLogger().isErrorEnabled()) {
+ StringBuffer exceptionBuffer =
+ new StringBuffer(128)
+ .append("Exception during connection from ")
+ .append(remoteHost)
+ .append(" (")
+ .append(remoteIP)
+ .append("): ")
+ .append(e.getMessage());
+ getLogger().error(exceptionBuffer.toString(),e);
}
}
/**
* Resets the handler data to a basic state.
*/
- private void resetHandler() {
-
- // Clear the Watchdog
- if (theWatchdog != null) {
- ContainerUtil.dispose(theWatchdog);
- theWatchdog = null;
- }
-
- in = null;
- out = null;
- try {
- if (socket != null) {
- socket.close();
- }
- } catch (IOException e) {
- if (getLogger().isErrorEnabled()) {
- getLogger().error("Exception closing socket: "
- + e.getMessage());
- }
- } finally {
- socket = null;
- }
-
- synchronized (this) {
- handlerThread = null;
- }
-
+ protected void resetHandler() {
// Reset user repository
users = theConfigData.getUsersRepository();
Modified: james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java?rev=404864&r1=404863&r2=404864&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java (original)
+++ james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java Sun May 7 15:36:08 2006
@@ -21,19 +21,12 @@
import org.apache.james.Constants;
import org.apache.james.core.AbstractJamesHandler;
import org.apache.james.util.CRLFTerminatedReader;
-import org.apache.james.util.InternetPrintWriter;
import org.apache.james.util.watchdog.Watchdog;
import org.apache.mailet.Mail;
import org.apache.mailet.dates.RFC822DateFormat;
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.OutputStreamWriter;
-import java.net.Socket;
-import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -107,26 +100,6 @@
private boolean sessionEnded = false;
/**
- * The incoming stream of bytes coming from the socket.
- */
- private InputStream in;
-
- /**
- * A Reader wrapper for the incoming stream of bytes coming from the socket.
- */
- private CRLFTerminatedReader inReader;
-
- /**
- * The remote host name obtained by lookup on the socket.
- */
- private String remoteHost;
-
- /**
- * The remote IP address of the socket.
- */
- private String remoteIP;
-
- /**
* The user name of the authenticated user associated with this SMTP transaction.
*/
private String authenticatedUser;
@@ -189,261 +162,151 @@
}
/**
- * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket)
+ * @see org.apache.james.core.AbstractJamesHandler#handleProtocol()
*/
- public void handleConnection(Socket connection) throws IOException {
-
- try {
- this.socket = connection;
- synchronized (this) {
- handlerThread = Thread.currentThread();
- }
- in = new BufferedInputStream(socket.getInputStream(), 1024);
- // An ASCII encoding can be used because all transmissions other
- // that those in the DATA command are guaranteed
- // to be ASCII
- // inReader = new BufferedReader(new InputStreamReader(in, "ASCII"), 512);
- inReader = new CRLFTerminatedReader(in, "ASCII");
- remoteIP = socket.getInetAddress().getHostAddress();
- remoteHost = socket.getInetAddress().getHostName();
- smtpID = random.nextInt(1024) + "";
- relayingAllowed = theConfigData.isRelayingAllowed(remoteIP);
- authRequired = theConfigData.isAuthRequired(remoteIP);
- heloEhloEnforcement = theConfigData.useHeloEhloEnforcement();
- sessionEnded = false;
- resetState();
- } catch (Exception e) {
- StringBuffer exceptionBuffer =
- new StringBuffer(256)
- .append("Cannot open connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append("): ")
- .append(e.getMessage());
- String exceptionString = exceptionBuffer.toString();
- getLogger().error(exceptionString, e );
- throw new RuntimeException(exceptionString);
- }
-
- if (getLogger().isInfoEnabled()) {
- StringBuffer infoBuffer =
- new StringBuffer(128)
- .append("Connection from ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(")");
- getLogger().info(infoBuffer.toString());
- }
-
- try {
-
- out = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()), 1024), false);
+ protected void handleProtocol() throws IOException {
+ smtpID = random.nextInt(1024) + "";
+ relayingAllowed = theConfigData.isRelayingAllowed(remoteIP);
+ authRequired = theConfigData.isAuthRequired(remoteIP);
+ heloEhloEnforcement = theConfigData.useHeloEhloEnforcement();
+ sessionEnded = false;
+ resetState();
- // Initially greet the connector
- // Format is: Sat, 24 Jan 1998 13:16:09 -0500
+ // Initially greet the connector
+ // Format is: Sat, 24 Jan 1998 13:16:09 -0500
- responseBuffer.append("220 ")
- .append(theConfigData.getHelloName())
- .append(" SMTP Server (")
- .append(SOFTWARE_TYPE)
- .append(") ready ")
- .append(rfc822DateFormat.format(new Date()));
- String responseString = clearResponseBuffer();
- writeLoggedFlushedResponse(responseString);
-
- //the core in-protocol handling logic
- //run all the connection handlers, if it fast fails, end the session
- //parse the command command, look up for the list of command handlers
- //Execute each of the command handlers. If any command handlers writes
- //response then, End the subsequent command handler processing and
- //start parsing new command. Once the message is received, run all
- //the message handlers. The message handlers can either terminate
- //message or terminate session
-
- //At the beginning
- //mode = command_mode
- //once the commandHandler writes response, the mode is changed to RESPONSE_MODE.
- //This will cause to skip the subsequent command handlers configured for that command.
- //For instance:
- //There are 2 commandhandlers MailAddressChecker and MailCmdHandler for
- //MAIL command. If MailAddressChecker validation of the MAIL FROM
- //address is successful, the MailCmdHandlers will be executed.
- //Incase it fails, it has to write response. Once we write response
- //there is no need to execute the MailCmdHandler.
- //Next, Once MAIL message is received the DataCmdHandler and any other
- //equivalent commandHandler will call setMail method. this will change
- //he mode to MAIL_RECEIVED_MODE. This mode will trigger the message
- //handlers to be execute. Message handlers can abort message. In that case,
- //message will not spooled.
-
- //Session started - RUN all connect handlers
- List connectHandlers = handlerChain.getConnectHandlers();
- if(connectHandlers != null) {
- int count = connectHandlers.size();
- for(int i = 0; i < count; i++) {
- ((ConnectHandler)connectHandlers.get(i)).onConnect(this);
- if(sessionEnded) {
- break;
- }
+ responseBuffer.append("220 ")
+ .append(theConfigData.getHelloName())
+ .append(" SMTP Server (")
+ .append(SOFTWARE_TYPE)
+ .append(") ready ")
+ .append(rfc822DateFormat.format(new Date()));
+ String responseString = clearResponseBuffer();
+ writeLoggedFlushedResponse(responseString);
+
+ //the core in-protocol handling logic
+ //run all the connection handlers, if it fast fails, end the session
+ //parse the command command, look up for the list of command handlers
+ //Execute each of the command handlers. If any command handlers writes
+ //response then, End the subsequent command handler processing and
+ //start parsing new command. Once the message is received, run all
+ //the message handlers. The message handlers can either terminate
+ //message or terminate session
+
+ //At the beginning
+ //mode = command_mode
+ //once the commandHandler writes response, the mode is changed to RESPONSE_MODE.
+ //This will cause to skip the subsequent command handlers configured for that command.
+ //For instance:
+ //There are 2 commandhandlers MailAddressChecker and MailCmdHandler for
+ //MAIL command. If MailAddressChecker validation of the MAIL FROM
+ //address is successful, the MailCmdHandlers will be executed.
+ //Incase it fails, it has to write response. Once we write response
+ //there is no need to execute the MailCmdHandler.
+ //Next, Once MAIL message is received the DataCmdHandler and any other
+ //equivalent commandHandler will call setMail method. this will change
+ //he mode to MAIL_RECEIVED_MODE. This mode will trigger the message
+ //handlers to be execute. Message handlers can abort message. In that case,
+ //message will not spooled.
+
+ //Session started - RUN all connect handlers
+ List connectHandlers = handlerChain.getConnectHandlers();
+ if(connectHandlers != null) {
+ int count = connectHandlers.size();
+ for(int i = 0; i < count; i++) {
+ ((ConnectHandler)connectHandlers.get(i)).onConnect(this);
+ if(sessionEnded) {
+ break;
}
}
+ }
- theWatchdog.start();
- while(!sessionEnded) {
- //Reset the current command values
- curCommandName = null;
- curCommandArgument = null;
- mode = COMMAND_MODE;
-
- //parse the command
- String cmdString = readCommandLine();
- if (cmdString == null) {
- break;
- }
- int spaceIndex = cmdString.indexOf(" ");
- if (spaceIndex > 0) {
- curCommandName = cmdString.substring(0, spaceIndex);
- curCommandArgument = cmdString.substring(spaceIndex + 1);
- } else {
- curCommandName = cmdString;
- }
- curCommandName = curCommandName.toUpperCase(Locale.US);
-
- //fetch the command handlers registered to the command
- List commandHandlers = handlerChain.getCommandHandlers(curCommandName);
- if(commandHandlers == null) {
- //end the session
- break;
- } else {
- int count = commandHandlers.size();
- for(int i = 0; i < count; i++) {
- ((CommandHandler)commandHandlers.get(i)).onCommand(this);
- theWatchdog.reset();
- //if the response is received, stop processing of command handlers
- if(mode != COMMAND_MODE) {
- break;
- }
+ theWatchdog.start();
+ while(!sessionEnded) {
+ //Reset the current command values
+ curCommandName = null;
+ curCommandArgument = null;
+ mode = COMMAND_MODE;
+
+ //parse the command
+ String cmdString = readCommandLine();
+ if (cmdString == null) {
+ break;
+ }
+ int spaceIndex = cmdString.indexOf(" ");
+ if (spaceIndex > 0) {
+ curCommandName = cmdString.substring(0, spaceIndex);
+ curCommandArgument = cmdString.substring(spaceIndex + 1);
+ } else {
+ curCommandName = cmdString;
+ }
+ curCommandName = curCommandName.toUpperCase(Locale.US);
+
+ //fetch the command handlers registered to the command
+ List commandHandlers = handlerChain.getCommandHandlers(curCommandName);
+ if(commandHandlers == null) {
+ //end the session
+ break;
+ } else {
+ int count = commandHandlers.size();
+ for(int i = 0; i < count; i++) {
+ ((CommandHandler)commandHandlers.get(i)).onCommand(this);
+ theWatchdog.reset();
+ //if the response is received, stop processing of command handlers
+ if(mode != COMMAND_MODE) {
+ break;
}
-
}
- //handle messages
- if(mode == MESSAGE_RECEIVED_MODE) {
- getLogger().info("executing message handlers");
- List messageHandlers = handlerChain.getMessageHandlers();
- int count = messageHandlers.size();
- for(int i =0; i < count; i++) {
- ((MessageHandler)messageHandlers.get(i)).onMessage(this);
- //if the response is received, stop processing of command handlers
- if(mode == MESSAGE_ABORT_MODE) {
- break;
- }
+ }
+
+ //handle messages
+ if(mode == MESSAGE_RECEIVED_MODE) {
+ getLogger().info("executing message handlers");
+ List messageHandlers = handlerChain.getMessageHandlers();
+ int count = messageHandlers.size();
+ for(int i =0; i < count; i++) {
+ ((MessageHandler)messageHandlers.get(i)).onMessage(this);
+ //if the response is received, stop processing of command handlers
+ if(mode == MESSAGE_ABORT_MODE) {
+ break;
}
}
+ }
- //do the clean up
- if(mail != null) {
- ContainerUtil.dispose(mail);
-
- // remember the ehlo mode
- Object currentHeloMode = state.get(CURRENT_HELO_MODE);
-
- mail = null;
- resetState();
-
- // start again with the old helo mode
- if (currentHeloMode != null) {
- state.put(CURRENT_HELO_MODE,currentHeloMode);
- }
+ //do the clean up
+ if(mail != null) {
+ ContainerUtil.dispose(mail);
+
+ // remember the ehlo mode
+ Object currentHeloMode = state.get(CURRENT_HELO_MODE);
+
+ mail = null;
+ resetState();
+
+ // start again with the old helo mode
+ if (currentHeloMode != null) {
+ state.put(CURRENT_HELO_MODE,currentHeloMode);
}
+ }
- }
- theWatchdog.stop();
- getLogger().debug("Closing socket.");
- } catch (SocketException se) {
- if (getLogger().isErrorEnabled()) {
- StringBuffer errorBuffer =
- new StringBuffer(64)
- .append("Socket to ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") closed remotely.");
- getLogger().error(errorBuffer.toString(), se );
- }
- } catch ( InterruptedIOException iioe ) {
- if (getLogger().isErrorEnabled()) {
- StringBuffer errorBuffer =
- new StringBuffer(64)
- .append("Socket to ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") timeout.");
- getLogger().error( errorBuffer.toString(), iioe );
- }
- } catch ( IOException ioe ) {
- if (getLogger().isErrorEnabled()) {
- StringBuffer errorBuffer =
- new StringBuffer(256)
- .append("Exception handling socket to ")
- .append(remoteHost)
- .append(" (")
- .append(remoteIP)
- .append(") : ")
- .append(ioe.getMessage());
- getLogger().error( errorBuffer.toString(), ioe );
- }
- } catch (Exception e) {
- if (getLogger().isErrorEnabled()) {
- getLogger().error( "Exception opening socket: "
- + e.getMessage(), e );
- }
- } finally {
- //Clear all the session state variables
- resetHandler();
}
+ theWatchdog.stop();
+ getLogger().debug("Closing socket.");
}
/**
* Resets the handler data to a basic state.
*/
- private void resetHandler() {
+ protected void resetHandler() {
resetState();
clearResponseBuffer();
- in = null;
- inReader = null;
- out = null;
+
remoteHost = null;
remoteIP = null;
authenticatedUser = null;
smtpID = null;
-
- if (theWatchdog != null) {
- ContainerUtil.dispose(theWatchdog);
- theWatchdog = null;
- }
-
- try {
- if (socket != null) {
- socket.close();
- }
- } catch (IOException e) {
- if (getLogger().isErrorEnabled()) {
- getLogger().error("Exception closing socket: "
- + e.getMessage());
- }
- } finally {
- socket = null;
- }
-
- synchronized (this) {
- handlerThread = null;
- }
-
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
James Handlers refactoring (Was: svn commit: r404864)
Posted by Stefano Bagnara <ap...@bago.org>.
I committed this as a work-in-progress proposal.
I'm happy with the result, so far, but it comes with a drawback.
In order to put most code in commons I had to change the "reader" used
by the RemoteManager from a BufferedReader to a CRLFTerminatedReader.
Imho this is not a big issue and most "telnet based" protocol enforce
this rule, but this introduce a small backward incompatibility issue.
The next step would be to separate commands in CmdHandler for
NNTP/RemoteManager and POP3 like we did for SMPTServer.
This would be a better structure to start adding new remoteManager
commands Norman already submitted to JIRA.
Please review the changes in *Handler and *Server and tell me what you
think.
Stefano
PS: Overall the refactoring on the Handler stuff reduced the source size
of James of 20K and remove a lot of duplicate code.
bago@apache.org wrote:
> Author: bago
> Date: Sun May 7 15:36:08 2006
> New Revision: 404864
>
> URL: http://svn.apache.org/viewcvs?rev=404864&view=rev
> Log:
> Further generalization in protocol handling. Now the 4 specific protocol handler are Avalon free (all the avalon stuff is in the AbstractJamesHandler) and they share most of the low-level protocol code.
> Please note that RemoteManagerHandler now uses the CRLFInputStreamReader so it now mandate a CRLF based communication.
>
> Modified:
> james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java
> james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java
> james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
> james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
> james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org
Re: James Handlers refactoring (Was: svn commit: r404864)
Posted by Norman Maurer <nm...@byteaction.de>.
Am Montag, den 08.05.2006, 00:54 +0200 schrieb Stefano Bagnara:
> I committed this as a work-in-progress proposal.
>
> I'm happy with the result, so far, but it comes with a drawback.
>
> In order to put most code in commons I had to change the "reader" used
> by the RemoteManager from a BufferedReader to a CRLFTerminatedReader.
>
> Imho this is not a big issue and most "telnet based" protocol enforce
> this rule, but this introduce a small backward incompatibility issue.
>
> The next step would be to separate commands in CmdHandler for
> NNTP/RemoteManager and POP3 like we did for SMPTServer.
That whould be a nice refactoring .. So it will be much easier to add
new commands without touch the "core". What about make SMTPHandler
execute more then one CmdHandler ber command ? What was the last state
for that ?
>
> This would be a better structure to start adding new remoteManager
> commands Norman already submitted to JIRA.
>
Right.. I also have some new features here. But i want to wait until i
know if the refactoring will be made..
> Please review the changes in *Handler and *Server and tell me what you
> think.
>
After a quick review i think its a good choice to remove ushc duplicate
code and but it in seperate classes..
> Stefano
>
> PS: Overall the refactoring on the Handler stuff reduced the source size
> of James of 20K and remove a lot of duplicate code.
>
> bago@apache.org wrote:
> > Author: bago
> > Date: Sun May 7 15:36:08 2006
> > New Revision: 404864
> >
> > URL: http://svn.apache.org/viewcvs?rev=404864&view=rev
> > Log:
> > Further generalization in protocol handling. Now the 4 specific protocol handler are Avalon free (all the avalon stuff is in the AbstractJamesHandler) and they share most of the low-level protocol code.
> > Please note that RemoteManagerHandler now uses the CRLFInputStreamReader so it now mandate a CRLF based communication.
> >
> > Modified:
> > james/server/trunk/src/java/org/apache/james/core/AbstractJamesHandler.java
> > james/server/trunk/src/java/org/apache/james/nntpserver/NNTPHandler.java
> > james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
> > james/server/trunk/src/java/org/apache/james/remotemanager/RemoteManagerHandler.java
> > james/server/trunk/src/java/org/apache/james/smtpserver/SMTPHandler.java
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
> For additional commands, e-mail: server-dev-help@james.apache.org
bye
Norman