package com.netifera.platform.net.sockets; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.concurrent.TimeUnit; public class LineChannel extends AsynchronousSocketChannel { final private AsynchronousByteChannel channel; private String separator = "\r\n"; final private Charset charset = Charset.forName("UTF-8"); final private StringBuffer inputBuffer = new StringBuffer(); public LineChannel(AsynchronousByteChannel channel) { this.channel = channel; } public void setSeparator(String separator) { this.separator = separator; } public <A> void writeLine(String line, final long timeout, final TimeUnit unit, A attachment, final CompletionHandler<Void,A> handler) { final ByteBuffer buffer = charset.encode(line+separator); channel.write(buffer, timeout, unit, attachment, new CompletionHandler<Integer,A>() { public void cancelled(A attachment) { handler.cancelled(attachment); } public void completed(Integer result, A attachment) { if (buffer.hasRemaining()) channel.write(buffer, timeout, unit, attachment, this); //FIXME timeout should decrement, not always the same handler.completed(null, attachment); } public void failed(Throwable exc, A attachment) { exc.printStackTrace(); handler.failed(exc, attachment); } }); } private String inputBufferReadLine() { int indexCR = inputBuffer.indexOf("\r"); int indexNL = inputBuffer.indexOf("\n"); int maxIndex = indexCR > indexNL ? indexCR : indexNL; if (maxIndex == -1) return null; int minIndex = indexCR == -1 ? indexNL : (indexCR < indexNL ? indexCR : indexNL); String line = inputBuffer.substring(0, minIndex); inputBuffer.replace(0, maxIndex+1, ""); return line; } public <A> void readLine(final long timeout, final TimeUnit unit, A attachment, final CompletionHandler<String,A> handler) { final ByteBuffer buffer = ByteBuffer.allocate(1024); String line = inputBufferReadLine(); if (line != null) { handler.completed(line, attachment); return; } channel.read(buffer, timeout, unit, attachment, new CompletionHandler<Integer,A>() { public void cancelled(A attachment) { handler.cancelled(attachment); } public void completed(Integer result, A attachment) { buffer.flip(); inputBuffer.append(charset.decode(buffer).toString()); String line = inputBufferReadLine(); if (line == null) channel.read(buffer, timeout, unit, attachment, this); else { handler.completed(line, attachment); } } public void failed(Throwable exc, A attachment) { handler.failed(exc, attachment); } }); } public void close() throws IOException { channel.close(); } }