package de.tum.in.www1.jReto.niotools;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
import java.util.Queue;
public class ChannelReader implements Dispatcher.ReadHandler<SocketChannel> {
public static interface ReadHandler {
public void onRead(ByteBuffer byteBuffer);
}
public static interface CloseHandler {
public void onClose();
}
public final SocketChannel socketChannel;
public final Dispatcher dispatcher;
public final ReadHandler handler;
public final CloseHandler closeHandler;
private final Queue<Integer> readRequests;
private ByteBuffer currentBuffer;
public ChannelReader(SocketChannel socketChannel, Dispatcher dispatcher, ReadHandler readHandler, CloseHandler closeHandler) {
if (socketChannel == null) throw new IllegalArgumentException("socketChannel may not be null");
if (dispatcher == null) throw new IllegalArgumentException("dispatcher may not be null");
if (readHandler == null) throw new IllegalArgumentException("readHandler may not be null");
if (closeHandler == null) throw new IllegalArgumentException("closeHandler may not be null");
this.readRequests = new LinkedList<Integer>();
this.socketChannel = socketChannel;
this.dispatcher = dispatcher;
this.handler = readHandler;
this.closeHandler = closeHandler;
}
public void read(int length) {
if (length <= 0) throw new IllegalArgumentException("length may not be <= 0");
if (this.readRequests.size() == 0 && currentBuffer == null) this.dispatcher.registerReadHandler(this, this.socketChannel);
this.readRequests.add(length);
processReadRequests();
}
private void processReadRequests() {
if (this.currentBuffer != null || readRequests.size() == 0) return;
int length = readRequests.poll();
this.currentBuffer = ByteBuffer.allocate(length);
}
private void readFromSocket() {
if (this.currentBuffer == null) return;
if (!this.socketChannel.isConnected()) {
System.out.println("Socket not connected, cannot read.");
return;
}
int bytesRead = -1;
try {
bytesRead = this.socketChannel.read(this.currentBuffer);
} catch (IOException e1) {
System.err.println("Exception occurred while reading from the socket. Closing the socket now.");
e1.printStackTrace();
}
if (bytesRead==-1) {
try {
this.dispatcher.unregister(this.socketChannel);
this.socketChannel.close();
} catch (IOException e) {
System.err.println("Exception occurred while closing connection. Continuing anyway.");
e.printStackTrace();
} finally {
this.closeHandler.onClose();
}
} else if (!this.currentBuffer.hasRemaining()) {
this.currentBuffer.clear();
this.handler.onRead(this.currentBuffer);
this.currentBuffer = null;
if (this.readRequests.size() == 0) this.dispatcher.unregisterRead(this.socketChannel);
processReadRequests();
}
}
public void onReadable(SocketChannel socket) {
this.readFromSocket();
}
}