package uk.nhs.kch.rassyeyanie.common.testing.integration;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*/
public abstract class AbstractListenerTest {
private static final Logger logger = LoggerFactory.getLogger(AbstractListenerTest.class);
private static final int CONNECT_TIMEOUT = 10000;
private static final Map<InetSocketAddress,NioSocketAcceptor> receivers = new HashMap<InetSocketAddress,NioSocketAcceptor>();
protected abstract IoHandler createClientHandler(String message);
/**
* Loads the contents of a specified file into a String. The file must be on the current classpath.
*/
protected String loadFile(String filename) throws IOException {
InputStream inputStream = getClass().getResourceAsStream(filename);
try {
String fileContents = IOUtils.toString(inputStream);
return fileContents.replaceAll("\n", "\r");
} finally {
inputStream.close();
}
}
/**
* Starts one or more listeners. There will be one unique listener for each port.
* Each listener will be assigned a handler defined by the createServerHandler() method.
* If the handler is shared then it should be made thread-safe.
*/
protected static void startReceivers(IoHandler serverHandler, InetSocketAddress... addresses) {
for (InetSocketAddress address : addresses) {
NioSocketAcceptor acceptor = receivers.get(address);
if (acceptor == null) {
createReceiver(serverHandler, address);
}
}
}
private static void createReceiver(IoHandler serverHandler, InetSocketAddress address) {
try {
NioSocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.setReuseAddress(true);
acceptor.setHandler(serverHandler);
acceptor.bind(address);
logger.info("Receiver started on port {}", address.getPort());
receivers.put(address, acceptor);
} catch (IOException ex) {
logger.error(ex.getMessage(), ex);
fail("Failed to start listener on port " + address.getPort());
}
}
/**
* Stops any currently running listeners. This method can be blocked by the sendMessage() method.
* Once all messages have been sent the listeners can be stopped.
*/
protected static void stopReceivers() {
// Dispose of any active listeners
for (Map.Entry<InetSocketAddress,NioSocketAcceptor> entry : receivers.entrySet()) {
IoAcceptor acceptor = entry.getValue();
ServerHandler handler = (ServerHandler)acceptor.getHandler();
try {
while (handler.isStillWaitingToSendMessages()) {
Thread.sleep(500L);
}
} catch (InterruptedException ex) {
logger.error(ex.getMessage(), ex);
}
acceptor.unbind();
acceptor.dispose();
logger.info("Receiver stopped on port {}", entry.getKey());
}
}
protected void sendMessage(InetSocketAddress address, String message, ServerHandler serverHandler, int expected) throws InterruptedException {
serverHandler.setExpectedMessageCount(expected);
sendMessage(message, address);
serverHandler.waitForMessages();
int actual = serverHandler.getMessageCount();
assertEquals("Number of messages received by server", expected, actual);
}
/**
* Sends a message to a specified port. The message itself is handled by the IoHandler
* created by the createClientHandler() method.
*/
private void sendMessage(String message, InetSocketAddress address) throws InterruptedException {
IoHandler clientHandler = createClientHandler(message);
NioSocketConnector connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(CONNECT_TIMEOUT);
connector.setHandler(clientHandler);
IoSession session = createClientSession(connector, address);
// wait until the message has been sent
session.getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
private IoSession createClientSession(NioSocketConnector connector, InetSocketAddress address) throws InterruptedException {
while (true) {
try {
ConnectFuture future = connector.connect(address);
future.awaitUninterruptibly();
return future.getSession();
} catch (RuntimeIoException e) {
logger.error(e.getMessage(), e);
Thread.sleep(5000);
}
}
}
}