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

org.fuwjax.oss.util.pipe.InputOutputStream Maven / Gradle / Ivy

Go to download

Java 8 Functional interface extentions, collection decorators, I/O interfaces, and assertions

The newest version!
/*
 * Copyright (C) 2015 fuwjax.org ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fuwjax.oss.util.pipe;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InputOutputStream {
	private InputStream in = new InputStream() {
		@Override
		public int read() throws IOException {
			lock.lock();
			try {
				while (!closing && readCapacity() == 0) {
					hasCapacity.await();
				}
				int b = forRead().get();
				hasCapacity.signalAll();
				return b;
			} catch (BufferUnderflowException e) {
				return -1;
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
				return -1;
			} finally {
				lock.unlock();
			}
		}

		@Override
		public int read(byte[] b, int off, int len) throws IOException {
			lock.lock();
			try {
				while (!closing && readCapacity() == 0) {
					hasCapacity.await();
				}
				int count = Math.min(readCapacity(), len);
				forRead().get(b, off, count);
				hasCapacity.signalAll();
				return count;
			} catch (BufferUnderflowException e) {
				return -1;
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
				return -1;
			} finally {
				lock.unlock();
			}
		}

		@Override
		public int available() throws IOException {
			return readCapacity();
		}

		@Override
		public void close() {
			InputOutputStream.this.close();
		}
	};

	private OutputStream out = new OutputStream() {
		@Override
		public void write(int b) throws IOException {
			lock.lock();
			try {
				while (!closing && writeCapacity() == 0) {
					hasCapacity.await();
				}
				forWrite().put((byte) b);
				hasCapacity.signalAll();
			} catch (BufferOverflowException e) {
				throw new IOException("cannot write after close");
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			} finally {
				lock.unlock();
			}
		}

		@Override
		public void write(byte[] b, int off, int len) throws IOException {
			int offset = off;
			int length = len;
			lock.lock();
			try {
				while (!closing && length > 0) {
					while (!closing && writeCapacity() == 0) {
						hasCapacity.await();
					}
					int count = Math.min(writeCapacity(), length);
					forWrite().put(b, offset, length);
					hasCapacity.signalAll();
					offset += count;
					length -= count;
				}
			} catch (BufferOverflowException e) {
				throw new IOException("cannot write after close");
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			} finally {
				lock.unlock();
			}
		}

		@Override
		public void close() {
			InputOutputStream.this.close();
		}
	};

	public enum Mode {
		READ, WRITE;
	}

	private final Lock lock = new ReentrantLock();
	private final Condition hasCapacity = lock.newCondition();
	private final ByteBuffer buffer = ByteBuffer.allocate(4096);
	private volatile Mode mode = Mode.WRITE;
	private volatile boolean closing;

	private int readCapacity() {
		return mode == Mode.WRITE ? buffer.position() : buffer.remaining();
	}

	private int writeCapacity() {
		return mode == Mode.WRITE ? buffer.remaining() : buffer.capacity() - buffer.remaining();
	}

	private ByteBuffer forRead() {
		if (mode == Mode.WRITE) {
			buffer.flip();
			mode = Mode.READ;
		}
		return buffer;
	}

	private ByteBuffer forWrite() {
		if (mode == Mode.READ) {
			buffer.compact();
			mode = Mode.WRITE;
		}
		return buffer;
	}

	public InputStream input() {
		return in;
	}

	public OutputStream output() {
		return out;
	}

	public void close() {
		closing = true;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy