package org.embulk.spi.util; import java.util.Arrays; import java.util.Iterator; import java.io.InputStream; import java.io.Closeable; import java.io.IOException; import org.embulk.spi.Buffer; import org.embulk.spi.FileInput; import org.embulk.spi.BufferAllocator; public class InputStreamFileInput implements FileInput { public interface Provider extends Closeable { public InputStream openNext() throws IOException; public void close() throws IOException; } public interface Opener { public InputStream open() throws IOException; } public static class IteratorProvider implements Provider { private Iterator<InputStream> iterator; public IteratorProvider(Iterable<InputStream> iterable) { this.iterator = iterable.iterator(); } public IteratorProvider(Iterator<InputStream> iterator) { this.iterator = iterator; } @Override public InputStream openNext() throws IOException { if (!iterator.hasNext()) { return null; } return iterator.next(); } @Override public void close() throws IOException { while (iterator.hasNext()) { iterator.next().close(); } } } private static class OpenerProvider implements Provider { private Opener opener; public OpenerProvider(Opener opener) { this.opener = opener; } @Override public InputStream openNext() throws IOException { if (opener == null) { return null; } InputStream stream = opener.open(); opener = null; return stream; } @Override public void close() throws IOException { } } private static class InputStreamProvider implements Provider { private InputStream input; public InputStreamProvider(InputStream input) { this.input = input; } @Override public InputStream openNext() throws IOException { if (input == null) { return null; } InputStream ret = input; input = null; return ret; } @Override public void close() throws IOException { if (input != null) { input.close(); input = null; } } } private final BufferAllocator allocator; private final Provider provider; private InputStream current; public InputStreamFileInput(BufferAllocator allocator, Provider provider) { this.allocator = allocator; this.provider = provider; this.current = null; } public InputStreamFileInput(BufferAllocator allocator, Opener opener) { this(allocator, new OpenerProvider(opener)); } public InputStreamFileInput(BufferAllocator allocator, InputStream openedStream) { this(allocator, new InputStreamProvider(openedStream)); } public Buffer poll() { if (current == null) { throw new IllegalStateException("nextFile() must be called before poll()"); } Buffer buffer = allocator.allocate(); try { int n = current.read(buffer.array(), buffer.offset(), buffer.capacity()); if (n < 0) { return null; } buffer.limit(n); Buffer b = buffer; buffer = null; return b; } catch (IOException ex) { throw new RuntimeException(ex); } finally { if (buffer != null) { buffer.release(); buffer = null; } } } public boolean nextFile() { try { if (current != null) { current.close(); current = null; } current = provider.openNext(); return current != null; } catch (IOException ex) { throw new RuntimeException(ex); } } public void close() { try { try { if (current != null) { current.close(); current = null; } } finally { provider.close(); } } catch (IOException ex) { throw new RuntimeException(ex); } } }