package org.simpleframework.common.buffer; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.simpleframework.common.buffer.Allocator; import org.simpleframework.common.buffer.Buffer; import org.simpleframework.common.buffer.BufferAllocator; public class FileByteQueue { private BlockingQueue<Block> blocks; private BlockAllocator allocator; private Block source; public FileByteQueue(Allocator allocator) throws IOException { this.blocks = new LinkedBlockingQueue<Block>(); this.allocator = new BlockAllocator(allocator); } public int read(byte[] array, int off, int size) throws Exception { int left = blocks.size(); int mark = size; for(int i = 0; source != null || i < left; i++) { if(source == null) { source = blocks.take(); } int remain = source.remaining(); int read = Math.min(remain, size); if(read > 0) { source.read(array, off, size); size -= read; off += read; } if(remain == 0) { source.close(); // clear up file handles source = null; } if(size <= 0) { return mark; } } return mark - size; } public void write(byte[] array, int off, int size) throws Exception { Block buffer = allocator.allocate(array, off, size); if(size > 0) { blocks.offer(buffer); } } private class BlockAllocator { private Allocator allocator; public BlockAllocator(Allocator allocator) { this.allocator = new BufferAllocator(allocator); } public Block allocate(byte[] array, int off, int size) throws IOException { Buffer buffer = allocator.allocate(); if(size > 0) { buffer.append(array, off, size); } return new Block(buffer, size); } } private class Block { private InputStream source; private int remaining; private int size; public Block(Buffer buffer, int size) throws IOException { this.source = buffer.open(); this.remaining = size; this.size = size; } public int read(byte[] array, int off, int size) throws IOException { int count = source.read(array, off, size); if(count > 0) { remaining -= size; } return count; } public void close() throws IOException { source.close(); } public int remaining() { return remaining; } public int size() { return size; } } }