package org.reunionemu.jreunion.network;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
public abstract class Connection<T extends Connection<T>> {
private ByteBuffer inputBuffer;
private ByteBuffer outputBuffer;
private SocketChannel socketChannel;
private boolean open = false;
public boolean isOpen() {
return open;
}
public SocketChannel getSocketChannel() {
return socketChannel;
}
private NetworkThread<T> networkThread;
public Connection(NetworkThread<T> networkThread, SocketChannel socketChannel) {
this.socketChannel = socketChannel;
this.networkThread = networkThread;
}
public void open() throws IOException{
inputBuffer = ByteBuffer.allocate(1024);
outputBuffer = ByteBuffer.allocate(1024);
Selector selector = networkThread.getSelector();
socketChannel.configureBlocking(false);
synchronized(this.networkThread){
if(selector.isOpen()){
selector.wakeup();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
key.attach(this);
}
}
open = true;
}
public void close(){
try {
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
handleDisconnect();
}
}
public NetworkThread<T> getNetworkThread() {
return networkThread;
}
public void write(byte [] data){
Selector selector = networkThread.getSelector();
try {
synchronized(outputBuffer){
outputBuffer.put(data);
synchronized(this.networkThread){
selector.wakeup();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
key.attach(this);
}
}
} catch (ClosedChannelException e) {
e.printStackTrace();
handleDisconnect();
}
}
void handleDisconnect(){
open = false;
SelectionKey key = socketChannel.keyFor(networkThread.getSelector());
if(key!=null){
key.cancel();
}
networkThread.onDisconnect((T)this);
}
protected byte [] getData(){
synchronized(inputBuffer){
inputBuffer.flip();
byte [] data = new byte[inputBuffer.limit()];
inputBuffer.get(data);
inputBuffer.clear();
return data;
}
}
public void onData(ByteBuffer inputBuffer){
throw new UnsupportedOperationException();
}
void handleInput() {
try {
int size = 0;
synchronized(inputBuffer){
size = socketChannel.read(inputBuffer);
}
if(size==-1){
handleDisconnect();
} else {
synchronized(inputBuffer){
onData(inputBuffer);
}
}
} catch (IOException e) {
//e.printStackTrace();
handleDisconnect();
}
}
void handleOutput() {
Selector selector = networkThread.getSelector();
try {
synchronized(outputBuffer){
outputBuffer.flip();
socketChannel.write(outputBuffer);
outputBuffer.clear();
synchronized(this.networkThread){
selector.wakeup();
SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
key.attach(this);
}
}
} catch (Exception e) {
e.printStackTrace();
handleDisconnect();
}
}
}