All Downloads are FREE. Search and download functionalities are using the official Maven repository.

koncept.nio.StreamedByteChannel Maven / Gradle / Ivy

package koncept.nio;

import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;


public class StreamedByteChannel implements Closeable, Flushable {

	private static final int capacity = 1024; //bytes
	
	private final ByteChannel chan;
	private volatile boolean closed = false;
	private final In in;
	private final Out out;
	
	private long readTimeout = -1;  //-1 = no timeout, 0 or more = elapsed ms timeout
	private long writeTimeout = -1; //-1 = no timeout, 0 or more = elapsed ms timeout
	
	public StreamedByteChannel(ByteChannel chan) {
		this.chan = chan;
		in = new In();
		out = new Out();
	}
	
	@Override
	public void close() throws IOException {
		out.flush();
		chan.close();
		closed = true;
	}
	
	@Override
	public void flush() throws IOException {
		out.flush();
	}
	
	public InputStream getIn() {
		return in;
	}
	
	public OutputStream getOut() {
		return out;
	}
	
	public void setWriteTimeout(long writeTimeout) {
		this.writeTimeout = writeTimeout;
	}
	
	public void setReadTimeout(long readTimeout) {
		this.readTimeout = readTimeout;
	}
	
	public class Out extends OutputStream {
		private final ByteBuffer buff = ByteBuffer.allocate(capacity);
		@Override
		public void write(int b) throws IOException {
			if(!buff.hasRemaining()) {
				if (writeTimeout >= 0) {
					long timeout = System.currentTimeMillis() + writeTimeout;
					while (!buff.hasRemaining() && timeout > System.currentTimeMillis() && !closed)
						flush();
				} else { //no timeout
					while (!buff.hasRemaining() && !closed)
						flush();
				}
			}
			
			buff.put((byte)b);
			if(!buff.hasRemaining())
				flush();
		}
		
		@Override
		public void flush() throws IOException {
			if (buff.position() == 0) 
				return; //nothing to do
			buff.flip(); //pos will now be 0
			try {
				chan.write(buff);
				if (buff.position() == 0) {
					if (writeTimeout >= 0) {
						long timeout = System.currentTimeMillis() + writeTimeout;
						while (buff.position() == 0 && timeout > System.currentTimeMillis() && !closed)
							chan.write(buff);
					} else { //no timeout
						while (buff.position() == 0 && !closed)
							chan.write(buff);
					}
				}
			} catch (IOException e) {
				closed = true;
				throw e;
			} finally {
			buff.compact();
			}
		}
		
		public long writeTimeout() {
			return writeTimeout;
		}
		
		public void writeTimeout(long writeTimeout) {
			StreamedByteChannel.this.writeTimeout = writeTimeout;
		}
		
		@Override
		public void close() throws IOException {
//			StreamedByteChannel.this.close();
		}
	}
	
	public class In extends InputStream {
		private final ByteBuffer buff = ByteBuffer.allocate(capacity);
		
		public In() {
			buff.flip();
		}
		
		@Override
		public int read() throws IOException {
			if(closed) return -1;
			if (!buff.hasRemaining() ) {
				poll(true);
	        }
			if (!buff.hasRemaining()) {
				return -1;
	        }
	        return buff.get() & 0xFF;
		}
		
		@Override
		public int read(byte[] b, int off, int len) throws IOException {
			if(closed) return -1;
			if (!buff.hasRemaining()) {
				poll(false);
	        }
			len = Math.min(len, available());
			for(int i = 0; i < len; i++) {
				b[i + off] = (byte)(buff.get() & 0xFF);
			}
			return len;
		}
		
		private void poll(boolean eligibleForWait) throws IOException {
			buff.compact();
			try {
				int currentPos = buff.position();
				
				//initial read
				chan.read(buff);
				if (eligibleForWait && buff.position() == currentPos) {
					if (readTimeout >= 0) {
						long timeout = System.currentTimeMillis() + readTimeout;
						while (buff.position() == currentPos && timeout > System.currentTimeMillis() && !closed) 
							 chan.read(buff);
					} else { //no timeout
						while (buff.position() == currentPos && !closed) 
							 chan.read(buff);
					}
				}
			} catch (IOException e) {
				closed = true;
				throw e;
			} finally {
				buff.flip();
			}
		}
		
		public long readTimeout() {
			return readTimeout;
		}
		
		public void readTimeout(long readTimeout) {
			StreamedByteChannel.this.readTimeout = readTimeout;
		}
		
		@Override
		public int available() throws IOException {
			return buff.remaining();
		}
		
		@Override
		public void close() throws IOException {
//			StreamedByteChannel.this.close();
		}
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy