package gov.nih.nci.cagrid.common; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Provides a central control point for writing data into a queue and * reading it back out asynchronously. * * @author David * */ public class ByteQueue { private ByteBuffer byteBuffer = null; private OutputStream output = null; private InputStream input = null; private boolean streamOpen; private Object writeLock = null; public ByteQueue(ByteBuffer buffer) { this.byteBuffer = buffer; this.output = new ByteQueueOutputStream(byteBuffer); this.input = new ByteQueueInputStream(byteBuffer); this.streamOpen = true; this.writeLock = new Object(); } public OutputStream getByteOutputStream() { return this.output; } public InputStream getByteInputStream() { return this.input; } public void cleanUp() { byteBuffer.cleanUp(); } public void finalize() { cleanUp(); } private class ByteQueueOutputStream extends OutputStream { private ByteBuffer buffer = null; private byte[] temp = null; private int bytesWritten; public ByteQueueOutputStream(ByteBuffer buffer) { this.buffer = buffer; this.temp = new byte[4096]; this.bytesWritten = 0; } public void flush() throws IOException { synchronized (writeLock) { buffer.appendData(temp, bytesWritten); bytesWritten = 0; writeLock.notifyAll(); } } public void close() throws IOException { synchronized (writeLock) { streamOpen = false; flush(); } } public void write(int b) throws IOException { temp[bytesWritten++] = (byte) b; if (bytesWritten == temp.length) { flush(); } } } private class ByteQueueInputStream extends InputStream { private static final int DEFAULT_BUFFER_LENGTH = 4096; private ByteBuffer buffer = null; private byte[] temp = null; private int tempIndex = 0; public ByteQueueInputStream(ByteBuffer buffer) { this.buffer = buffer; } public int read() throws IOException { if (temp == null || tempIndex == temp.length) { temp = buffer.extractData(DEFAULT_BUFFER_LENGTH); while (temp.length == 0 && streamOpen) { // no data to read, but more should be coming in! // wait for the writer side of things to notify us synchronized (writeLock) { try { writeLock.wait(); } catch (InterruptedException ex) { ex.printStackTrace(); throw new IOException("Error waiting for data: " + ex.getMessage()); } } temp = buffer.extractData(DEFAULT_BUFFER_LENGTH); } tempIndex = 0; } int i = -1; if (temp.length != 0) { i = temp[tempIndex]; tempIndex++; } return i; } } }