package org.playorm.nio.impl.cm.basic;
import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.playorm.nio.api.channels.NioException;
import org.playorm.nio.api.channels.TCPChannel;
import org.playorm.nio.api.channels.TCPServerChannel;
import org.playorm.nio.api.handlers.ConnectionListener;
import org.playorm.nio.api.handlers.DataListener;
import org.playorm.nio.api.libs.BufferFactory;
import org.playorm.nio.api.testutil.chanapi.ChannelsFactory;
/**
* @author Dean Hiller
*/
class BasTCPServerChannel extends RegisterableChannelImpl implements TCPServerChannel {
private static final Logger log = Logger.getLogger(BasTCPServerChannel.class.getName());
private ServerSocketChannel channel;
private int i = 0;
private BufferFactory bufFactory;
private ChannelsFactory channelFactory;
public BasTCPServerChannel(IdObject id, ChannelsFactory c, BufferFactory bufFactory, SelectorManager2 selMgr) throws IOException {
super(id, selMgr);
this.bufFactory = bufFactory;
this.channelFactory = c;
channel = ServerSocketChannel.open();
channel.configureBlocking(false);
}
public int getSession() {
return i++;
}
/* (non-Javadoc)
* @see api.biz.xsoftware.nio.TCPServerChannel#accept()
*/
public void accept(String newSocketId, ConnectionListener cb) throws IOException {
if(cb == null)
throw new IllegalArgumentException("cb is not allowed to be null");
try {
//special code...see information in close() method
if(isClosed())
return;
SocketChannel newChan = channel.accept();
if(newChan == null)
return;
newChan.configureBlocking(false);
org.playorm.nio.api.testutil.chanapi.SocketChannel proxyChan = channelFactory.open(newChan);
IdObject obj = new IdObject(getIdObject(), newSocketId);
TCPChannel tcpChan = new BasTCPChannel(obj, bufFactory, proxyChan, getSelectorManager());
if(log.isLoggable(Level.FINER))
log.finer(tcpChan+"Accepted new incoming connection");
cb.connected(tcpChan);
} catch(Throwable e) {
log.log(Level.WARNING, this+"Failed to connect", e);
cb.failed(this, e);
}
}
public void registerForReads(DataListener listener) throws IOException, InterruptedException {
throw new UnsupportedOperationException("TCPServerChannel's can't read, they can only accept incoming connections");
}
public void registerServerSocketChannel(ConnectionListener cb) {
if(!isBound())
throw new IllegalArgumentException("Only bound sockets can be registered or selector doesn't work");
try {
getSelectorManager().registerServerSocketChannel(this, cb);
} catch (IOException e) {
throw new NioException(e);
} catch (InterruptedException e) {
throw new NioException(e);
}
}
public void bind(SocketAddress srvrAddr) {
try {
bindImpl(srvrAddr);
} catch (IOException e) {
throw new NioException(e);
}
}
/* (non-Javadoc)
* @see api.biz.xsoftware.nio.TCPServerChannel#bind(java.net.SocketAddress)
*/
private void bindImpl(SocketAddress srvrAddr) throws IOException {
try {
channel.socket().bind(srvrAddr);
} catch(BindException e) {
BindException ee = new BindException("bind exception on addr="+srvrAddr);
ee.initCause(e);
throw ee;
}
}
public boolean isBound() {
return channel.socket().isBound();
}
public void oldClose() {
//socket.close was resulting in following exception on polling thread.
//To fix this, we put mechanisms in place to look if this channel
//was closed or not on the call to accept method
//
//INFO: [[client]][ClientChannel] READ 0 bytes(this is strange)
//Feb 19, 2006 6:01:22 AM biz.xsoftware.impl.nio.cm.basic.TCPServerChannelImpl accept
//WARNING: [[server]][TCPServerChannel] Failed to connect
//java.nio.channels.ClosedChannelException
//at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:130)
//at biz.xsoftware.impl.nio.cm.basic.TCPServerChannelImpl.accept(TCPServerChannelImpl.java:61)
//at biz.xsoftware.impl.nio.cm.basic.Helper.acceptSocket(Helper.java:109)
//at biz.xsoftware.impl.nio.cm.basic.Helper.processKey(Helper.java:82)
//at biz.xsoftware.impl.nio.cm.basic.Helper.processKeys(Helper.java:47)
//at biz.xsoftware.impl.nio.cm.basic.SelectorManager2.runLoop(SelectorManager2.java:305)
//at biz.xsoftware.impl.nio.cm.basic.SelectorManager2$PollingThread.run(SelectorManager2.java:267)
try {
channel.socket().close();
channel.close();
super.wakeupSelector();
} catch(Exception e) {
log.log(Level.WARNING, this+"Exception closing channel", e);
}
}
public boolean isClosed() {
return channel.socket().isClosed();
}
/**
*/
public SelectableChannel getRealChannel() {
return channel;
}
/* (non-Javadoc)
* @see api.biz.xsoftware.nio.RegisterableChannel#isBlocking()
*/
public boolean isBlocking() {
return channel.isBlocking();
}
/* (non-Javadoc)
* @see api.biz.xsoftware.nio.RegisterableChannel#setReuseAddress(boolean)
*/
public void setReuseAddress(boolean b) {
try {
channel.socket().setReuseAddress(b);
} catch (SocketException e) {
throw new NioException(e);
}
}
/* (non-Javadoc)
* @see api.biz.xsoftware.nio.SocketSuperclass#getLocalAddress()
*/
public InetSocketAddress getLocalAddress() {
InetAddress addr = channel.socket().getInetAddress();
int port = channel.socket().getLocalPort();
return new InetSocketAddress(addr, port);
}
}