diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-08 22:39:59 -0300 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-08 22:39:59 -0300 |
| commit | c82e3b3b2de0633317ec8fc85925e91422820597 (patch) | |
| tree | 96567416ce23c5ce85601f9cedc3a94bb1c55cba /base/src/main/java/bjc/utils/ioutils/blocks | |
| parent | b3ac1c8690c3e14c879913e5dcc03a5f5e14876e (diff) | |
Start splitting into maven modules
Diffstat (limited to 'base/src/main/java/bjc/utils/ioutils/blocks')
13 files changed, 1077 insertions, 0 deletions
diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/Block.java b/base/src/main/java/bjc/utils/ioutils/blocks/Block.java new file mode 100644 index 0000000..15f3510 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/Block.java @@ -0,0 +1,88 @@ +package bjc.utils.ioutils.blocks; + +/** + * Represents a block of text read in from a source. + * + * @author EVE + * + */ +public class Block { + /** + * The contents of this block. + */ + public final String contents; + + /** + * The line of the source this block started on. + */ + public final int startLine; + + /** + * The line of the source this block ended on. + */ + public final int endLine; + + /** + * The number of this block. + */ + public final int blockNo; + + /** + * Create a new block. + * + * @param blockNo + * The number of this block. + * @param contents + * The contents of this block. + * @param startLine + * The line this block started on. + * @param endLine + * The line this block ended. + */ + public Block(final int blockNo, final String contents, final int startLine, final int endLine) { + this.contents = contents; + this.startLine = startLine; + this.endLine = endLine; + this.blockNo = blockNo; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + blockNo; + result = prime * result + (contents == null ? 0 : contents.hashCode()); + result = prime * result + endLine; + result = prime * result + startLine; + + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Block)) return false; + + final Block other = (Block) obj; + + if (blockNo != other.blockNo) return false; + + if (contents == null) { + if (other.contents != null) return false; + } else if (!contents.equals(other.contents)) return false; + + if (endLine != other.endLine) return false; + if (startLine != other.startLine) return false; + + return true; + } + + @Override + public String toString() { + String fmt = "Block #%d (from lines %d to %d), length: %d characters"; + + return String.format(fmt, blockNo, startLine, endLine, contents.length()); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java new file mode 100644 index 0000000..3c695c6 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/BlockReader.java @@ -0,0 +1,73 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Iterator; +import java.util.function.Consumer; + +/** + * A source of blocks of characters, marked with line numbers as to block + * start/block end. + * + * @author bjculkin + * + */ +public interface BlockReader extends AutoCloseable, Iterator<Block> { + /** + * Check if this reader has an available block. + * + * @return Whether or not another block is available. + */ + boolean hasNextBlock(); + + /** + * Get the current block. + * + * @return The current block, or null if there is no current block. + */ + Block getBlock(); + + /** + * Move to the next block. + * + * @return Whether or not the next block was successfully read. + */ + boolean nextBlock(); + + /** + * Retrieve the number of blocks that have been read so far. + * + * @return The number of blocks read so far. + */ + int getBlockCount(); + + @Override + void close() throws IOException; + + /* + * Methods with default impls. + */ + + /** + * Execute an action for each remaining block. + * + * @param action + * The action to execute for each block + */ + default void forEachBlock(final Consumer<Block> action) { + while (hasNext()) { + action.accept(next()); + } + } + + @Override + default boolean hasNext() { + return hasNextBlock(); + } + + @Override + default Block next() { + nextBlock(); + + return getBlock(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java b/base/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java new file mode 100644 index 0000000..8bbb89c --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/BlockReaders.java @@ -0,0 +1,81 @@ +package bjc.utils.ioutils.blocks; + +import java.io.Reader; + +/** + * Utility methods for constructing instances of {@link BlockReader} + * + * @author bjculkin + * + */ +public class BlockReaders { + /** + * Create a new simple block reader that works off a regex. + * + * @param blockDelim + * The regex that separates blocks. + * + * @param source + * The reader to get blocks from. + * + * @return A configured simple reader. + */ + public static SimpleBlockReader simple(final String blockDelim, final Reader source) { + return new SimpleBlockReader(blockDelim, source); + } + + /** + * Create a new pushback block reader. + * + * @param src + * The block reader to read blocks from. + * + * @return A configured pushback reader. + */ + public static PushbackBlockReader pushback(final BlockReader src) { + return new PushbackBlockReader(src); + } + + /** + * Create a new triggered block reader. + * + * @param source + * The block reader to read blocks from. + * + * @param action + * The action to execute before reading a block. + * + * @return A configured triggered block reader. + */ + public static BlockReader trigger(final BlockReader source, final Runnable action) { + return new TriggeredBlockReader(source, action); + } + + /** + * Create a new layered block reader. + * + * @param primary + * The first source to read blocks from. + * + * @param secondary + * The second source to read blocks from. + * + * @return A configured layered block reader. + */ + public static BlockReader layered(final BlockReader primary, final BlockReader secondary) { + return new LayeredBlockReader(primary, secondary); + } + + /** + * Create a new serial block reader. + * + * @param readers + * The readers to pull from, in the order to pull from + * them. + * + * @return A configured serial block reader. + */ + public static BlockReader serial(final BlockReader... readers) { + return new SerialBlockReader(readers); + } +}
\ No newline at end of file diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/BoundBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/BoundBlockReader.java new file mode 100644 index 0000000..b1e82d7 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/BoundBlockReader.java @@ -0,0 +1,61 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +import java.util.function.BooleanSupplier; +import java.util.function.Supplier; + +public class BoundBlockReader implements BlockReader { + @FunctionalInterface + public interface Closer { + public void close() throws IOException; + } + + private BooleanSupplier checker; + private Supplier<Block> getter; + private Closer closer; + + private Block current; + + private int blockNo; + + public BoundBlockReader(BooleanSupplier blockChecker, Supplier<Block> blockGetter, Closer blockCloser) { + checker = blockChecker; + getter = blockGetter; + closer = blockCloser; + + blockNo = 0; + } + + @Override + public boolean hasNextBlock() { + return checker.getAsBoolean(); + } + + @Override + public Block getBlock() { + return current; + } + + @Override + public boolean nextBlock() { + if(checker.getAsBoolean()) { + current = getter.get(); + blockNo += 1; + + return true; + } + + return false; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + closer.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/FilteredBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/FilteredBlockReader.java new file mode 100644 index 0000000..0b43f7a --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/FilteredBlockReader.java @@ -0,0 +1,97 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class FilteredBlockReader implements BlockReader { + /* + * The source of blocks. + */ + private BlockReader source; + + /* + * The current and next block. + * + * Both have already been checked for the predicate. + */ + private Block current; + private Block pending; + + /* + * Number of blocks that passed the predicate. + */ + private int blockNo; + + /* + * The predicate blocks must pass. + */ + private Predicate<Block> pred; + + /* + * The action to call on failure, if there is one. + */ + private Consumer<Block> failAction; + + public FilteredBlockReader(BlockReader src, Predicate<Block> predic) { + this(src, predic, null); + } + + public FilteredBlockReader(BlockReader src, Predicate<Block> predic, Consumer<Block> failAct) { + source = src; + pred = predic; + failAction = failAct; + + blockNo = 0; + } + + @Override + public boolean hasNextBlock() { + if(pending != null) return true; + + while(source.hasNextBlock()) { + /* + * Only say we have a next block if the next block would + * pass the predicate. + */ + pending = source.next(); + + if(pred.test(pending)) { + blockNo += 1; + return true; + } else { + failAction.accept(pending); + } + } + + return false; + } + + @Override + public Block getBlock() { + return current; + } + + @Override + public boolean nextBlock() { + if(pending != null || hasNextBlock()) { + current = pending; + pending = null; + + return true; + } + + return false; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + source.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/FlatMappedBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/FlatMappedBlockReader.java new file mode 100644 index 0000000..f4d8439 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/FlatMappedBlockReader.java @@ -0,0 +1,86 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * A block reader that supports applying a flatmap operation to blocks. + * + * The use-case in mind for this was tokenizing blocks. + * + * @author Benjamin Culkin + */ +public class FlatMappedBlockReader implements BlockReader { + /* + * The source reader. + */ + private BlockReader reader; + + /* + * The current block, and any blocks pending from the last source block. + */ + private Iterator<Block> pending; + private Block current; + + /* + * The operator to open blocks with. + */ + private Function<Block, List<Block>> transform; + + /* + * The current block number. + */ + private int blockNo; + + public FlatMappedBlockReader(BlockReader source, Function<Block, List<Block>> trans) { + reader = source; + transform = trans; + + blockNo = 0; + } + + @Override + public boolean hasNextBlock() { + return pending.hasNext() || reader.hasNextBlock(); + } + + @Override + public Block getBlock() { + return current; + } + + @Override + public boolean nextBlock() { + /* + * Attempt to get a new pending list if the one we have isn't + * valid. + */ + while(pending == null || !pending.hasNext()) { + if(!reader.hasNext()) return false; + + pending = transform.apply(reader.next()).iterator(); + } + + /* + * Advance the iterator. + */ + current = pending.next(); + blockNo += 1; + + return true; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + reader.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java new file mode 100644 index 0000000..967a1f2 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/LayeredBlockReader.java @@ -0,0 +1,81 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +/** + * A block reader that supports draining all the blocks from one reading before + * swapping to another. + * + * This is more a 'prioritize blocks from one over the other', than a 'read all + * the blocks from one, then all the blocks from the other'. If you need that, + * look at {@link SerialBlockReader}. + * + * @author bjculkin + * + */ +public class LayeredBlockReader implements BlockReader { + /* + * The readers to drain from. + */ + private final BlockReader first; + private final BlockReader second; + + /* + * The current block number. + */ + private int blockNo; + + /** + * Create a new layered block reader. + * + * @param primary + * The first source to read blocks from. + * + * @param secondary + * The second source to read blocks from. + */ + public LayeredBlockReader(final BlockReader primary, final BlockReader secondary) { + first = primary; + second = secondary; + } + + @Override + public boolean hasNextBlock() { + return first.hasNextBlock() || second.hasNextBlock(); + } + + @Override + public Block getBlock() { + final Block firstBlock = first.getBlock(); + + /* + * Only drain a block from the second reader if none are + * available in the first reader. + */ + return firstBlock == null ? second.getBlock() : firstBlock; + } + + @Override + public boolean nextBlock() { + final boolean gotFirst = first.nextBlock(); + final boolean succ = gotFirst ? gotFirst : second.nextBlock(); + + if (succ) { + blockNo += 1; + } + + return succ; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + second.close(); + + first.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/MappedBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/MappedBlockReader.java new file mode 100644 index 0000000..12fa848 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/MappedBlockReader.java @@ -0,0 +1,54 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +import java.util.function.UnaryOperator; + +public class MappedBlockReader implements BlockReader { + private BlockReader reader; + + private Block current; + + private UnaryOperator<Block> transform; + + private int blockNo; + + public MappedBlockReader(BlockReader source, UnaryOperator<Block> trans) { + reader = source; + transform = trans; + + blockNo = 0; + } + + @Override + public boolean hasNextBlock() { + return reader.hasNextBlock(); + } + + @Override + public Block getBlock() { + return current; + } + + @Override + public boolean nextBlock() { + if(hasNextBlock()) { + current = transform.apply(reader.next()); + blockNo += 1; + + return true; + } + + return false; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + reader.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java new file mode 100644 index 0000000..0cc9dea --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/PushbackBlockReader.java @@ -0,0 +1,106 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Deque; +import java.util.LinkedList; + +/** + * A block reader that supports pushing blocks onto the input queue so that they + * are provided before blocks read from an input source. + * + * @author bjculkin + * + */ +public class PushbackBlockReader implements BlockReader { + private final BlockReader source; + + /* + * The queue of pushed-back blocks. + */ + private final Deque<Block> waiting; + + private Block curBlock; + + private int blockNo; + + /** + * Create a new pushback block reader. + * + * @param src + * The block reader to use when no blocks are queued. + */ + public PushbackBlockReader(final BlockReader src) { + source = src; + + waiting = new LinkedList<>(); + } + + @Override + public boolean hasNextBlock() { + return !waiting.isEmpty() || source.hasNextBlock(); + } + + @Override + public Block getBlock() { + return curBlock; + } + + @Override + public boolean nextBlock() { + /* + * Drain pushed-back blocks first. + */ + if (!waiting.isEmpty()) { + curBlock = waiting.pop(); + + blockNo += 1; + + return true; + } else { + final boolean succ = source.nextBlock(); + curBlock = source.getBlock(); + + if (succ) { + blockNo += 1; + } + + return succ; + } + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + source.close(); + } + + /** + * Insert a block at the back of the queue of pending blocks. + * + * @param blk + * The block to put at the back. + */ + public void addBlock(final Block blk) { + waiting.add(blk); + } + + /** + * Insert a block at the front of the queue of pending blocks. + * + * @param blk + * The block to put at the front. + */ + public void pushBlock(final Block blk) { + waiting.push(blk); + } + + @Override + public String toString() { + return String.format("PushbackBlockReader [waiting=%s, curBlock=%s, blockNo=%s]", waiting, curBlock, + blockNo); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java new file mode 100644 index 0000000..c229da1 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java @@ -0,0 +1,102 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.util.Deque; + +/** + * Provides a means of concatenating two block readers. + * + * @author bjculkin + * + */ +public class SerialBlockReader implements BlockReader { + private Deque<BlockReader> readerQueue; + + private int blockNo; + + /** + * Create a new serial block reader. + * + * @param readers + * The readers to pull from, in the order to pull from + * them. + */ + public SerialBlockReader(final BlockReader... readers) { + for (final BlockReader reader : readers) { + readerQueue.add(reader); + } + } + + @Override + public boolean hasNextBlock() { + if (readerQueue.isEmpty()) return false; + + /* + * Attempt to get a block from the first reader. + */ + boolean hasBlock = readerQueue.peek().hasNextBlock(); + boolean cont = hasBlock || readerQueue.isEmpty(); + + /* + * Close/dispose of readers until we get an open one. + */ + while (!cont) { + try { + readerQueue.pop().close(); + } catch (final IOException ioex) { + throw new IllegalStateException("Exception thrown by discarded reader", ioex); + } + + hasBlock = readerQueue.peek().hasNextBlock(); + cont = hasBlock || readerQueue.isEmpty(); + } + + return hasBlock; + } + + @Override + public Block getBlock() { + if (readerQueue.isEmpty()) + return null; + else return readerQueue.peek().getBlock(); + } + + @Override + public boolean nextBlock() { + if (readerQueue.isEmpty()) return false; + + boolean gotBlock = readerQueue.peek().nextBlock(); + boolean cont = gotBlock || readerQueue.isEmpty(); + + while (!cont) { + try { + readerQueue.pop().close(); + } catch (final IOException ioex) { + throw new IllegalStateException("Exception thrown by discarded reader", ioex); + } + + gotBlock = readerQueue.peek().nextBlock(); + cont = gotBlock || readerQueue.isEmpty(); + } + + if (cont) { + blockNo += 1; + } + + return cont; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + while (!readerQueue.isEmpty()) { + final BlockReader reader = readerQueue.pop(); + + reader.close(); + } + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java new file mode 100644 index 0000000..734bde8 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java @@ -0,0 +1,115 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.Reader; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.regex.Pattern; + +import bjc.utils.funcutils.StringUtils; +/** + * Simple implementation of {@link BlockReader} + * + * NOTE: The EOF marker is always treated as a delimiter. You are expected to + * handle blocks that may be shorter than you expect. + * + * @author EVE + * + */ +public class SimpleBlockReader implements BlockReader { + /* + * I/O source for blocks. + */ + private final Scanner blockReader; + + /* + * The current block. + */ + private Block currBlock; + + /* + * Info about the current block. + */ + private int blockNo; + private int lineNo; + + /** + * Create a new block reader. + * + * @param blockDelim + * The pattern that separates blocks. Note that the end + * of file is always considered to end a block. + * + * @param source + * The source to read blocks from. + */ + public SimpleBlockReader(final String blockDelim, final Reader source) { + blockReader = new Scanner(source); + + final String pattern = String.format("(?:%s)|\\Z", blockDelim); + final Pattern pt = Pattern.compile(pattern, Pattern.MULTILINE); + + blockReader.useDelimiter(pt); + + lineNo = 1; + } + + @Override + public boolean hasNextBlock() { + return blockReader.hasNext(); + } + + @Override + public Block getBlock() { + return currBlock; + } + + @Override + public boolean nextBlock() { + try { + /* + * Read in a new block, and keep the line numbers sane. + */ + final int blockStartLine = lineNo; + final String blockContents = blockReader.next(); + final int blockEndLine = lineNo + StringUtils.countMatches(blockContents, "\\R"); + + lineNo = blockEndLine; + blockNo += 1; + + currBlock = new Block(blockNo, blockContents, blockStartLine, blockEndLine); + + return true; + } catch (final NoSuchElementException nseex) { + currBlock = null; + + return false; + } + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + blockReader.close(); + } + + /** + * Set the delimiter used to separate blocks. + * + * @param delim + * The delimiter used to separate blocks. + */ + public void setDelimiter(final String delim) { + blockReader.useDelimiter(delim); + } + + @Override + public String toString() { + return String.format("SimpleBlockReader [currBlock=%s, blockNo=%s]", currBlock, blockNo); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/ToggledBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/ToggledBlockReader.java new file mode 100644 index 0000000..8f39b8f --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/ToggledBlockReader.java @@ -0,0 +1,63 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +import bjc.utils.data.BooleanToggle; + +public class ToggledBlockReader implements BlockReader { + private BlockReader leftSource; + private BlockReader rightSource; + + /* + * We choose the left source when this is true. + */ + private BooleanToggle leftToggle; + + private int blockNo; + + public ToggledBlockReader(BlockReader left, BlockReader right) { + leftSource = left; + rightSource = right; + + blockNo = 0; + + leftToggle = new BooleanToggle(); + } + + @Override + public boolean hasNextBlock() { + if(leftToggle.peek()) return leftSource.hasNextBlock(); + else return rightSource.hasNextBlock(); + } + + @Override + public Block getBlock() { + if(leftToggle.peek()) return leftSource.getBlock(); + else return rightSource.getBlock(); + } + + @Override + public boolean nextBlock() { + boolean succ; + + if(leftToggle.get()) { + succ = leftSource.nextBlock(); + } else { + succ = rightSource.nextBlock(); + } + + if(succ) blockNo += 1; + return succ; + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + leftSource.close(); + rightSource.close(); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java new file mode 100644 index 0000000..3a1e393 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/blocks/TriggeredBlockReader.java @@ -0,0 +1,70 @@ +package bjc.utils.ioutils.blocks; + +import java.io.IOException; + +/** + * A block reader that fires an action before a block is actually read. + * + * @author bjculkin + * + */ +public class TriggeredBlockReader implements BlockReader { + private final BlockReader source; + + private int blockNo; + + /* + * The action to fire. + */ + private final Runnable action; + + /** + * Create a new triggered reader with the specified source/action. + * + * @param source + * The block reader to read blocks from. + * + * @param action + * The action to execute before reading a block. + */ + public TriggeredBlockReader(final BlockReader source, final Runnable action) { + this.source = source; + this.action = action; + + blockNo = 0; + } + + @Override + public boolean hasNextBlock() { + action.run(); + + return source.hasNextBlock(); + } + + @Override + public Block getBlock() { + return source.getBlock(); + } + + @Override + public boolean nextBlock() { + blockNo += 1; + + return source.nextBlock(); + } + + @Override + public int getBlockCount() { + return blockNo; + } + + @Override + public void close() throws IOException { + source.close(); + } + + @Override + public String toString() { + return String.format("TriggeredBlockReader [source=%s]", source); + } +} |
