package org.playorm.nio.api.testutil; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.DatagramChannel; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.playorm.nio.api.channels.Channel; import org.playorm.nio.api.channels.RegisterableChannel; import org.playorm.nio.api.channels.TCPChannel; import org.playorm.nio.api.channels.TCPServerChannel; import org.playorm.nio.api.deprecated.ChannelService; import org.playorm.nio.api.deprecated.Settings; import org.playorm.nio.api.handlers.ConnectionListener; import org.playorm.nio.api.handlers.DataChunk; import org.playorm.nio.api.handlers.DataListener; /** * @author Dean Hiller */ public class MockNIOServer extends MockDataHandler implements ConnectionListener { public static final String CONNECTED = "connected"; public static final String CONN_FAILED = "failed"; private static final Logger log = Logger.getLogger(MockNIOServer.class.getName()); private ChannelService chanMgr; private TCPServerChannel srvrChannel; private List<TCPChannel> sockets = new LinkedList<TCPChannel>(); private Settings factoryHolder; private DatagramChannel udp; private DatagramReceiver recThread; public MockNIOServer(ChannelService svr, Settings h) throws UnknownHostException { super(); this.chanMgr = svr; this.factoryHolder = h; } public InetSocketAddress start() throws IOException, InterruptedException { int port = 0; chanMgr.start(); InetAddress loopBack = InetAddress.getByName("127.0.0.1"); InetSocketAddress svrAddr = new InetSocketAddress(loopBack, port); srvrChannel = chanMgr.createTCPServerChannel("TCPServerChannel", factoryHolder); srvrChannel.setReuseAddress(true); srvrChannel.bind(svrAddr); srvrChannel.registerServerSocketChannel(this); udp = DatagramChannel.open(); udp.configureBlocking(true); log.info("port="+srvrChannel.getLocalAddress().getPort()); InetSocketAddress udpAddr = new InetSocketAddress(loopBack, srvrChannel.getLocalAddress().getPort()+1); udp.socket().bind(udpAddr); recThread = new DatagramReceiver(udp, this); recThread.start(); return srvrChannel.getLocalAddress(); } public void stop() throws IOException, InterruptedException { recThread.stopThread(); udp.close(); log.info("close srvrChannel"); srvrChannel.oldClose(); log.info("oldClose channels"); for(int i = 0; i < sockets.size(); i++) { Channel channel = sockets.get(i); channel.oldClose(); } log.info("chanmgr stop"); //NOTE: Keep this stop here after closing the channels at sometimes //there are bugs there and they will show up this way. chanMgr.stop(); log.info("mock is stopped"); } /* (non-Javadoc) * @see biz.xsoftware.testlib.MockSuperclass#clone(java.lang.Object) */ protected Object clone(Object o) { return o; } public void connected(Channel channel) throws IOException { try { log.fine(channel+"mockserver accepted connection"); sockets.add((TCPChannel) channel); channel.registerForReads(MockNIOServer.this); methodCalled(CONNECTED, channel); } catch (RuntimeException e) { log.log(Level.WARNING, "Exception", e); //puts exception on test thread. methodCalled(CONNECTED, e); } } public void failed(RegisterableChannel channel, Throwable e) { methodCalled(CONN_FAILED, e); } public String toString() { return chanMgr.toString(); } public DatagramChannel getUDPServerChannel() { return udp; } private static class DatagramReceiver extends Thread { private ByteBuffer buffer; private DatagramChannel udp; private boolean stop = false; private DataListener handler; public DatagramReceiver(DatagramChannel udp, DataListener handler) { this.udp = udp; this.handler = handler; buffer = ByteBuffer.allocate(6000); } public void stopThread() { stop = true; this.interrupt(); } @Override public void run() { while(!stop) { try { buffer.clear(); udp.receive(buffer); buffer.flip(); DataChunk c = new DataChunk() { @Override public void setProcessed(String name) { } @Override public ByteBuffer getData() { return buffer; } }; handler.incomingData(null, c); } catch(ClosedByInterruptException e) { //occurs when thread is interrupted } catch(Exception e) { log.log(Level.WARNING, "Failure", e); handler.failure(null, buffer, e); } } } } }