/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.tools;
import java.net.ServerSocket;
import java.util.Iterator;
import org.springframework.beans.DirectFieldAccessor;
import com.dumbster.smtp.SimpleSmtpServer;
import com.dumbster.smtp.SmtpMessage;
/** Dummy smtp server used for testing.
*
* This server is based on dumbster, but adds the possibility to start in an OS
* selected port.
*/
public final class DummySmtpServer implements Iterable<SmtpMessage> {
/** The created SimpleSmtpServer.
*
* This is never null.
*/
private SimpleSmtpServer server;
/** Private constructor.
*
* @param smtpServer The dumbster smtp server wrapped by this class. It is
* never null.
*/
private DummySmtpServer(final SimpleSmtpServer smtpServer) {
server = smtpServer;
}
/** Creates a dummy smtp server and starts it.
*
* @param port the port number that the server will listen to.
*
* @return the created dummy server, never null.
*/
public static DummySmtpServer start(final int port) {
// This was copied from SimpleSmtpServer start operation, which has a race
// condition: t.start calls notifyAll(), that is intended to wake this
// thread that is waiting in server.
//
// The race happens because t.start may call notifyAll before this method
// calls server.wait. We just moved t.start to the synchronized block. This
// forces the new thread to wait until we this method calls server.wait().
SimpleSmtpServer server = new SimpleSmtpServer(port);
Thread t = new Thread(server);
// Block until the server socket is created
synchronized (server) {
t.start();
try {
server.wait();
} catch (InterruptedException e) {
// Ignore don't care.
}
}
return new DummySmtpServer(server);
}
/** Stops the server.
*
* Server is shutdown after processing of the current request is complete.
*/
public synchronized void stop() {
server.stop();
}
/** Obtains the port number where the server bound to.
*
* This operation is specially useful when the server is asked to start in
* port 0, where the operating system selects the port number.
*
* @return an integer with the port number.
*/
public synchronized int getPortNumber() {
DirectFieldAccessor accesor = new DirectFieldAccessor(server);
ServerSocket socket;
socket = (ServerSocket) accesor.getPropertyValue("serverSocket");
return socket.getLocalPort();
}
/** Get email received by this instance since start up.
*
* @return an iterator for all the received emails.
*/
@SuppressWarnings("unchecked")
public synchronized Iterator<SmtpMessage> iterator() {
return (Iterator<SmtpMessage>) server.getReceivedEmail();
}
/** Gets the number of messages received.
*
* @return size of received email list.
*/
public synchronized int getReceivedEmailSize() {
return server.getReceivedEmailSize();
}
}