diff --git a/runner/src/main/java/com/widen/tabitha/runner/Runner.java b/runner/src/main/java/com/widen/tabitha/runner/Runner.java index 91f6892..92a234a 100644 --- a/runner/src/main/java/com/widen/tabitha/runner/Runner.java +++ b/runner/src/main/java/com/widen/tabitha/runner/Runner.java @@ -9,21 +9,15 @@ import java.io.IOException; import java.io.InputStream; -public class Runner -{ +public class Runner { private static File scriptFile; - public static void main(String[] args) throws IOException - { - for (String arg : args) - { - if (arg.equals("-h") || arg.equals("--help") || arg.equals("-?") || arg.equals("/?")) - { + public static void main(String[] args) throws IOException { + for (String arg : args) { + if (arg.equals("-h") || arg.equals("--help") || arg.equals("-?") || arg.equals("/?")) { printHelp(); return; - } - else - { + } else { scriptFile = new File(arg); break; } @@ -32,15 +26,13 @@ public static void main(String[] args) throws IOException execute(); } - private static void printHelp() throws IOException - { + private static void printHelp() throws IOException { InputStream inputStream = Runner.class.getClassLoader().getResourceAsStream("Help.txt"); String text = IOUtils.toString(inputStream, "UTF-8"); System.out.println(text); } - private static void execute() throws IOException - { + private static void execute() throws IOException { ImportCustomizer importCustomizer = new ImportCustomizer(); importCustomizer.addStarImports("com.widen.tabitha"); importCustomizer.addStarImports("com.widen.tabitha.formats"); diff --git a/src/main/java/com/widen/tabitha/Column.java b/src/main/java/com/widen/tabitha/Column.java index f282091..521dc60 100644 --- a/src/main/java/com/widen/tabitha/Column.java +++ b/src/main/java/com/widen/tabitha/Column.java @@ -3,8 +3,7 @@ /** * A column in a schema. */ -public final class Column -{ +public final class Column { /** * The name of the column. */ @@ -15,10 +14,8 @@ public final class Column * * @param name The column name. */ - Column(String name) - { - if (name == null) - { + Column(String name) { + if (name == null) { throw new NullPointerException(); } @@ -26,8 +23,7 @@ public final class Column } @Override - public String toString() - { + public String toString() { return name; } } diff --git a/src/main/java/com/widen/tabitha/DataFrame.java b/src/main/java/com/widen/tabitha/DataFrame.java index c87a691..09645f7 100644 --- a/src/main/java/com/widen/tabitha/DataFrame.java +++ b/src/main/java/com/widen/tabitha/DataFrame.java @@ -19,8 +19,7 @@ * contain different columns than each other and there is no way for a data frame to know all the possible columns it * may contain. */ -public class DataFrame implements Iterable, Closeable -{ +public class DataFrame implements Iterable, Closeable { private final RingBuffer rows; private RowReader rowReader; @@ -30,8 +29,7 @@ public class DataFrame implements Iterable, Closeable * @param rowReader The row reader used to stream in data. * @return A new data frame. */ - public static DataFrame streaming(RowReader rowReader) - { + public static DataFrame streaming(RowReader rowReader) { DataFrame dataFrame = new DataFrame(); dataFrame.rowReader = rowReader; @@ -41,8 +39,7 @@ public static DataFrame streaming(RowReader rowReader) /** * Create a new in-memory data frame. */ - public DataFrame() - { + public DataFrame() { rows = new RingBuffer<>(); rowReader = null; } @@ -52,8 +49,7 @@ public DataFrame() * * @param rows The rows to put in the data frame. */ - public DataFrame(Row... rows) - { + public DataFrame(Row... rows) { this.rows = new RingBuffer<>(rows); rowReader = null; } @@ -63,8 +59,7 @@ public DataFrame(Row... rows) * * @return True if this is a streaming data frame. */ - public boolean isStreaming() - { + public boolean isStreaming() { return rowReader != null; } @@ -73,8 +68,7 @@ public boolean isStreaming() * * @return True if the data frame contains no elements. */ - public boolean isEmpty() - { + public boolean isEmpty() { return rows.isEmpty(); } @@ -83,8 +77,7 @@ public boolean isEmpty() * * @return The data frame size. */ - public int size() - { + public int size() { return rows.size(); } @@ -96,25 +89,18 @@ public int size() * @param index The index of the row to get. * @return The row, or none if the index does not exist. */ - public Optional get(int index) - { - if (isStreaming()) - { - while (index >= size()) - { - try - { + public Optional get(int index) { + if (isStreaming()) { + while (index >= size()) { + try { Row row = rowReader.read().orElse(null); - if (row == null) - { + if (row == null) { break; } pushBack(row); - } - catch (IOException e) - { + } catch (IOException e) { throw new RuntimeException(e); } } @@ -128,8 +114,7 @@ public Optional get(int index) * * @param row The row to push */ - public void pushFront(Row row) - { + public void pushFront(Row row) { rows.pushFront(row); } @@ -138,8 +123,7 @@ public void pushFront(Row row) * * @param row The row to push */ - public void pushBack(Row row) - { + public void pushBack(Row row) { rows.pushBack(row); } @@ -150,16 +134,11 @@ public void pushBack(Row row) * * @return The removed row, or none if the data frame is empty. */ - public Optional popFront() - { - if (isEmpty() && isStreaming()) - { - try - { + public Optional popFront() { + if (isEmpty() && isStreaming()) { + try { return rowReader.read(); - } - catch (IOException e) - { + } catch (IOException e) { throw new RuntimeException(e); } } @@ -174,16 +153,11 @@ public Optional popFront() * * @return The removed row, or none if the data frame is empty. */ - public Optional popBack() - { - if (isEmpty() && isStreaming()) - { - try - { + public Optional popBack() { + if (isEmpty() && isStreaming()) { + try { return rowReader.read(); - } - catch (IOException e) - { + } catch (IOException e) { throw new RuntimeException(e); } } @@ -196,8 +170,7 @@ public Optional popBack() * * @return The row reader. */ - public RowReader reader() - { + public RowReader reader() { return RowReader.from(iterator()); } @@ -206,15 +179,13 @@ public RowReader reader() * * @return The row writer. */ - public RowWriter writer() - { + public RowWriter writer() { // This creates a row writer using a method reference as the implementation for write(). return this::pushBack; } @Override - public Iterator iterator() - { + public Iterator iterator() { return rows.iterator(); } @@ -227,10 +198,8 @@ public Iterator iterator() * @throws IOException Thrown if an I/O error occurs. */ @Override - public void close() throws IOException - { - if (rowReader != null) - { + public void close() throws IOException { + if (rowReader != null) { rowReader.close(); rowReader = null; } diff --git a/src/main/java/com/widen/tabitha/Row.java b/src/main/java/com/widen/tabitha/Row.java index ed8c857..a355920 100644 --- a/src/main/java/com/widen/tabitha/Row.java +++ b/src/main/java/com/widen/tabitha/Row.java @@ -8,8 +8,7 @@ /** * Stores a single row of data values, indexed by column. */ -public class Row implements Iterable -{ +public class Row implements Iterable { private final Row.Cell[] cells; /** @@ -18,12 +17,10 @@ public class Row implements Iterable * @param rows The rows to merge. * @return The merged row. */ - public static Row merge(Row... rows) - { + public static Row merge(Row... rows) { List cells = new ArrayList<>(); - for (int i = 0; i < rows.length; ++i) - { + for (int i = 0; i < rows.length; ++i) { cells.addAll(Arrays.asList(rows[i].cells)); } @@ -35,8 +32,7 @@ public static Row merge(Row... rows) * * @param cells The cells to contain. */ - Row(Cell... cells) - { + Row(Cell... cells) { this.cells = cells; } @@ -45,8 +41,7 @@ public static Row merge(Row... rows) * * @return The number of values in the row. */ - public int size() - { + public int size() { return cells.length; } @@ -56,12 +51,9 @@ public int size() * @param name The name of the column. * @return The value for the given column, if present. */ - public Optional get(String name) - { - for (Cell cell : cells) - { - if (cell.column.name.equals(name)) - { + public Optional get(String name) { + for (Cell cell : cells) { + if (cell.column.name.equals(name)) { return Optional.of(cell.value); } } @@ -75,10 +67,8 @@ public Optional get(String name) * @param index The index of the column. * @return The value for the given column, if present. */ - public Optional get(int index) - { - if (index >= cells.length) - { + public Optional get(int index) { + if (index >= cells.length) { return Optional.empty(); } @@ -90,8 +80,7 @@ public Optional get(int index) * * @return Array of columns. */ - public Column[] columns() - { + public Column[] columns() { return Utils.mapArray(cells, Column.class, cell -> cell.column); } @@ -100,8 +89,7 @@ public Column[] columns() * * @return Array of values. */ - public Variant[] values() - { + public Variant[] values() { return Utils.mapArray(cells, Variant.class, cell -> cell.value); } @@ -111,12 +99,10 @@ public Variant[] values() * @param mapper A function to apply to each cell value. * @return The new row. */ - public Row map(Function mapper) - { + public Row map(Function mapper) { Cell[] mapped = new Cell[cells.length]; - for (int i = 0; i < mapped.length; ++i) - { + for (int i = 0; i < mapped.length; ++i) { mapped[i] = new Cell(cells[i].column, mapper.apply(cells[i].value)); } @@ -129,15 +115,12 @@ public Row map(Function mapper) * @param columns The names of columns to keep. * @return The new row. */ - public Row select(String... columns) - { + public Row select(String... columns) { List columnsToRetain = Arrays.asList(columns); ArrayList cells = new ArrayList<>(); - for (Cell cell : this) - { - if (columnsToRetain.contains(cell.column.name)) - { + for (Cell cell : this) { + if (columnsToRetain.contains(cell.column.name)) { cells.add(cell); } } @@ -149,13 +132,11 @@ public Row select(String... columns) * Get a new row that contains the values for only columns in the given range. * * @param start The start index, inclusive. - * @param end The ending index, exclusive. + * @param end The ending index, exclusive. * @return The new row. */ - public Row range(int start, int end) - { - if (start < 0 || end > cells.length) - { + public Row range(int start, int end) { + if (start < 0 || end > cells.length) { throw new IndexOutOfBoundsException(); } @@ -163,16 +144,14 @@ public Row range(int start, int end) } @Override - public Iterator iterator() - { + public Iterator iterator() { return new ArrayIterator<>(cells); } /** * A single cell from a row containing a value. */ - public static final class Cell - { + public static final class Cell { /** * The column the cell belongs to. */ @@ -187,12 +166,10 @@ public static final class Cell * Create a new cell. * * @param column The cell column. - * @param value The cell value. + * @param value The cell value. */ - Cell(Column column, Variant value) - { - if (column == null || value == null) - { + Cell(Column column, Variant value) { + if (column == null || value == null) { throw new NullPointerException(); } diff --git a/src/main/java/com/widen/tabitha/RowReader.java b/src/main/java/com/widen/tabitha/RowReader.java index 4ff6a12..a627ffe 100644 --- a/src/main/java/com/widen/tabitha/RowReader.java +++ b/src/main/java/com/widen/tabitha/RowReader.java @@ -12,11 +12,10 @@ * Reads data rows from a data source. */ @FunctionalInterface -public interface RowReader extends Iterable, Closeable -{ +public interface RowReader extends Iterable, Closeable { /** * A row reader that produces no rows. - * + *

* Closing has no effect on this row reader and is always re-usable. */ RowReader VOID = Optional::empty; @@ -27,17 +26,13 @@ public interface RowReader extends Iterable, Closeable * @param rows Rows to create from. * @return The new reader. */ - static RowReader from(Row... rows) - { - return new RowReader() - { + static RowReader from(Row... rows) { + return new RowReader() { private int index = 0; @Override - public Optional read() throws IOException - { - if (index < rows.length) - { + public Optional read() throws IOException { + if (index < rows.length) { return Optional.of(rows[index++]); } @@ -48,19 +43,17 @@ public Optional read() throws IOException /** * Create a row reader from an iterator. - * + *

* Calling {@link #read} on the returned row reader will advance the iterator if more items remain, or return empty * when the end of the iterator is reached. * * @param iterator Iterator to create from. * @return The new reader. */ - static RowReader from(Iterator iterator) - { + static RowReader from(Iterator iterator) { return () -> { - if (iterator.hasNext()) - { + if (iterator.hasNext()) { return Optional.of(iterator.next()); } @@ -74,8 +67,7 @@ static RowReader from(Iterator iterator) * @param iterable Iterable to create from. * @return The new reader. */ - static RowReader from(Iterable iterable) - { + static RowReader from(Iterable iterable) { return from(iterable.iterator()); } @@ -85,8 +77,7 @@ static RowReader from(Iterable iterable) * @param stream Stream to create from. * @return The new reader. */ - static RowReader from(Stream stream) - { + static RowReader from(Stream stream) { return from(stream.iterator()); } @@ -96,21 +87,16 @@ static RowReader from(Stream stream) * @param rowReaders The row readers to chain. * @return The chained reader. */ - static RowReader chain(RowReader... rowReaders) - { - return new RowReader() - { + static RowReader chain(RowReader... rowReaders) { + return new RowReader() { private int index = 0; @Override - public Optional read() throws IOException - { - while (index < rowReaders.length) - { + public Optional read() throws IOException { + while (index < rowReaders.length) { Optional row = rowReaders[index].read(); - if (row.isPresent()) - { + if (row.isPresent()) { return row; } @@ -121,10 +107,8 @@ public Optional read() throws IOException } @Override - public void close() throws IOException - { - for (RowReader rowReader : rowReaders) - { + public void close() throws IOException { + for (RowReader rowReader : rowReaders) { rowReader.close(); } } @@ -137,47 +121,36 @@ public void close() throws IOException * @param rowReaders Another row reader to join with. * @return The joined row reader. */ - static RowReader zip(RowReader... rowReaders) - { - return new RowReader() - { + static RowReader zip(RowReader... rowReaders) { + return new RowReader() { private final Row[] rows = new Row[rowReaders.length]; private boolean stillMore = true; @Override - public Optional read() throws IOException - { - if (!stillMore) - { + public Optional read() throws IOException { + if (!stillMore) { return Optional.empty(); } // Read one row from all readers. stillMore = false; - for (int i = 0; i < rows.length; ++i) - { + for (int i = 0; i < rows.length; ++i) { rows[i] = rowReaders[i].read().orElse(null); - if (rows[i] != null) - { + if (rows[i] != null) { stillMore = true; } } - if (stillMore) - { + if (stillMore) { return Optional.of(Row.merge(rows)); - } - else - { + } else { return Optional.empty(); } } @Override - public void close() throws IOException - { - for (RowReader rowReader : rowReaders) - { + public void close() throws IOException { + for (RowReader rowReader : rowReaders) { rowReader.close(); } } @@ -187,8 +160,8 @@ public void close() throws IOException /** * Attempt to read the next row. * - * @throws IOException Thrown if an I/O error occurs. * @return The next row if read, or an empty {@link Optional} if the end of the reader has been reached. + * @throws IOException Thrown if an I/O error occurs. */ Optional read() throws IOException; @@ -198,17 +171,12 @@ public void close() throws IOException * @param predicate A predicate to apply to each row to determine if it should be included. * @return A filtered reader. */ - default RowReader filter(Predicate predicate) - { - return new RowReader() - { + default RowReader filter(Predicate predicate) { + return new RowReader() { @Override - public Optional read() throws IOException - { - for (Row row : RowReader.this) - { - if (predicate.test(row)) - { + public Optional read() throws IOException { + for (Row row : RowReader.this) { + if (predicate.test(row)) { return Optional.of(row); } } @@ -217,8 +185,7 @@ public Optional read() throws IOException } @Override - public void close() throws IOException - { + public void close() throws IOException { RowReader.this.close(); } }; @@ -228,12 +195,11 @@ public void close() throws IOException * Filter rows returned based on the value of a given column. If the given column is not set for a row, that row is * filtered out. * - * @param column The column to filter by. + * @param column The column to filter by. * @param predicate A predicate to apply to each value in the column to determine if the row should be included. * @return A filtered row reader. */ - default RowReader filterBy(String column, Predicate predicate) - { + default RowReader filterBy(String column, Predicate predicate) { return filter(row -> row.get(column) .map(predicate::test) .orElse(false)); @@ -245,19 +211,15 @@ default RowReader filterBy(String column, Predicate predicate) * @param mapper A function to apply to each row. * @return A mapped reader. */ - default RowReader map(Function mapper) - { - return new RowReader() - { + default RowReader map(Function mapper) { + return new RowReader() { @Override - public Optional read() throws IOException - { + public Optional read() throws IOException { return RowReader.this.read().map(mapper); } @Override - public void close() throws IOException - { + public void close() throws IOException { RowReader.this.close(); } }; @@ -269,8 +231,7 @@ public void close() throws IOException * @param columns The names of columns to keep. * @return The new row reader. */ - default RowReader select(String... columns) - { + default RowReader select(String... columns) { return map(row -> row.select(columns)); } @@ -278,11 +239,10 @@ default RowReader select(String... columns) * Get a new row reader that returns the values for only columns in the given range. * * @param start The start index, inclusive. - * @param end The ending index, exclusive. + * @param end The ending index, exclusive. * @return The new row reader. */ - default RowReader range(int start, int end) - { + default RowReader range(int start, int end) { return map(row -> row.range(start, end)); } @@ -292,17 +252,13 @@ default RowReader range(int start, int end) * @param count The number of rows to skip. * @return The new row reader. */ - default RowReader skip(int count) - { - return new RowReader() - { + default RowReader skip(int count) { + return new RowReader() { private int skipped = 0; @Override - public Optional read() throws IOException - { - while (skipped < count) - { + public Optional read() throws IOException { + while (skipped < count) { RowReader.this.read(); ++skipped; } @@ -311,8 +267,7 @@ public Optional read() throws IOException } @Override - public void close() throws IOException - { + public void close() throws IOException { RowReader.this.close(); } }; @@ -324,21 +279,16 @@ public void close() throws IOException * @param count The maximum number of rows to read. * @return The new row reader. */ - default RowReader take(int count) - { - return new RowReader() - { + default RowReader take(int count) { + return new RowReader() { private int index = 0; @Override - public Optional read() throws IOException - { - if (index < count) - { + public Optional read() throws IOException { + if (index < count) { Optional row = RowReader.this.read(); - if (row.isPresent()) - { + if (row.isPresent()) { ++index; } @@ -349,8 +299,7 @@ public Optional read() throws IOException } @Override - public void close() throws IOException - { + public void close() throws IOException { RowReader.this.close(); } }; @@ -362,32 +311,23 @@ public void close() throws IOException * @param rowWriter A row writer to write all rows to. * @throws IOException Thrown if an I/O error occurs. */ - default void pipe(RowWriter rowWriter) throws IOException - { - for (Row row : this) - { + default void pipe(RowWriter rowWriter) throws IOException { + for (Row row : this) { rowWriter.write(row); } } @Override - default Iterator iterator() - { - return new Iterator() - { + default Iterator iterator() { + return new Iterator() { private Row nextRow; @Override - public boolean hasNext() - { - if (nextRow == null) - { - try - { + public boolean hasNext() { + if (nextRow == null) { + try { nextRow = read().orElse(null); - } - catch (IOException e) - { + } catch (IOException e) { return false; } } @@ -396,16 +336,11 @@ public boolean hasNext() } @Override - public Row next() - { - if (nextRow == null) - { - try - { + public Row next() { + if (nextRow == null) { + try { nextRow = read().orElse(null); - } - catch (IOException e) - { + } catch (IOException e) { return null; } } @@ -419,7 +354,6 @@ public Row next() // Provide a default close method that does nothing. @Override - default void close() throws IOException - { + default void close() throws IOException { } } diff --git a/src/main/java/com/widen/tabitha/RowReaderFactory.java b/src/main/java/com/widen/tabitha/RowReaderFactory.java index 7daa21e..0d8e326 100644 --- a/src/main/java/com/widen/tabitha/RowReaderFactory.java +++ b/src/main/java/com/widen/tabitha/RowReaderFactory.java @@ -14,20 +14,18 @@ /** * Helper factory methods for creating row readers. */ -public class RowReaderFactory -{ +public class RowReaderFactory { /** * Create a new row reader for the given file path and guess the format based on the filename. */ - public static RowReader createReader(String path) throws IOException - { + public static RowReader createReader(String path) throws IOException { return createReader(new File(path)); } + /** * Create a new row reader for the given input file and guess the format based on the filename. */ - public static RowReader createReader(File file) throws IOException - { + public static RowReader createReader(File file) throws IOException { InputStream inputStream = FileUtils.openInputStream(file); String filename = file.getName(); @@ -37,24 +35,18 @@ public static RowReader createReader(File file) throws IOException /** * Create a new row reader for the given input stream and guess the format based on a filename. */ - public static RowReader createReader(InputStream inputStream, String filename) throws IOException - { + public static RowReader createReader(InputStream inputStream, String filename) throws IOException { String extension = FilenameUtils.getExtension(filename); - if ("xlsx".equals(extension) || "xls".equals(extension)) - { - try - { + if ("xlsx".equals(extension) || "xls".equals(extension)) { + try { return new ExcelRowReader(inputStream); - } - catch (InvalidFormatException e) - { + } catch (InvalidFormatException e) { // Not an Excel format. } } - if ("tsv".equals(extension)) - { + if ("tsv".equals(extension)) { return new DelimitedRowReader(inputStream, DelimitedTextFormat.TSV); } diff --git a/src/main/java/com/widen/tabitha/RowWriter.java b/src/main/java/com/widen/tabitha/RowWriter.java index d2cd847..7623669 100644 --- a/src/main/java/com/widen/tabitha/RowWriter.java +++ b/src/main/java/com/widen/tabitha/RowWriter.java @@ -7,14 +7,14 @@ * Writes data rows to an output. */ @FunctionalInterface -public interface RowWriter extends Closeable -{ +public interface RowWriter extends Closeable { /** * A row writer that discards all rows written to it. - * + *

* Closing has no effect on this row writer and is always re-usable. */ - RowWriter VOID = row -> {}; + RowWriter VOID = row -> { + }; /** * Creates a new row writer that writes rows to multiple destinations. @@ -22,24 +22,18 @@ public interface RowWriter extends Closeable * @param rowWriters The writers to write to. * @return The new row writer. */ - static RowWriter tee(RowWriter... rowWriters) - { - return new RowWriter() - { + static RowWriter tee(RowWriter... rowWriters) { + return new RowWriter() { @Override - public void write(Row row) throws IOException - { - for (RowWriter rowWriter : rowWriters) - { + public void write(Row row) throws IOException { + for (RowWriter rowWriter : rowWriters) { rowWriter.write(row); } } @Override - public void close() throws IOException - { - for (RowWriter rowWriter : rowWriters) - { + public void close() throws IOException { + for (RowWriter rowWriter : rowWriters) { rowWriter.close(); } } @@ -60,17 +54,14 @@ public void close() throws IOException * @param rows The rows to write. * @throws IOException Thrown if an I/O error occurs. */ - default void writeAll(Row... rows) throws IOException - { - for (Row row : rows) - { + default void writeAll(Row... rows) throws IOException { + for (Row row : rows) { write(row); } } // Provide a default close method that does nothing. @Override - default void close() throws IOException - { + default void close() throws IOException { } } diff --git a/src/main/java/com/widen/tabitha/RowWriterFactory.java b/src/main/java/com/widen/tabitha/RowWriterFactory.java index c539e0b..40eb5cc 100644 --- a/src/main/java/com/widen/tabitha/RowWriterFactory.java +++ b/src/main/java/com/widen/tabitha/RowWriterFactory.java @@ -13,21 +13,18 @@ /** * Helper factory methods for creating row writers. */ -public class RowWriterFactory -{ +public class RowWriterFactory { /** * Create a new row writer for the given file path and guess the output format based on the filename. */ - public static RowWriter createWriter(String path) throws IOException - { + public static RowWriter createWriter(String path) throws IOException { return createWriter(new File(path)); } /** * Create a new row writer for the given output file and guess the output format based on the filename. */ - public static RowWriter createWriter(File file) throws IOException - { + public static RowWriter createWriter(File file) throws IOException { OutputStream outputStream = FileUtils.openOutputStream(file); String filename = file.getName(); @@ -37,22 +34,18 @@ public static RowWriter createWriter(File file) throws IOException /** * Create a new row writer for the given output stream and guess the output format based on a filename. */ - public static RowWriter createWriter(OutputStream outputStream, String filename) - { + public static RowWriter createWriter(OutputStream outputStream, String filename) { String extension = FilenameUtils.getExtension(filename); - if ("xlsx".equals(extension)) - { + if ("xlsx".equals(extension)) { return new ExcelRowWriter(outputStream, false); } - if ("xls".equals(extension)) - { + if ("xls".equals(extension)) { return new ExcelRowWriter(outputStream, true); } - if ("tsv".equals(extension)) - { + if ("tsv".equals(extension)) { return new DelimitedRowWriter(outputStream, DelimitedTextFormat.TSV); } diff --git a/src/main/java/com/widen/tabitha/Schema.java b/src/main/java/com/widen/tabitha/Schema.java index b037abd..212af92 100644 --- a/src/main/java/com/widen/tabitha/Schema.java +++ b/src/main/java/com/widen/tabitha/Schema.java @@ -8,8 +8,7 @@ /** * Defines a list of columns. Used to create rows that follow the schema. */ -public class Schema implements Iterable -{ +public class Schema implements Iterable { // Ordered list of columns. private Column[] columnsByIndex; @@ -18,23 +17,19 @@ public class Schema implements Iterable /** * Create a new column index that combines all the columns in the given indexes. - * + *

* Columns are ordered from left to right the order of the indexes given. * * @param schemas The schemas to merge. * @return The merged schema. * @throws DuplicateColumnException if duplicate column names are found. */ - public static Schema merge(Schema... schemas) - { + public static Schema merge(Schema... schemas) { Builder builder = new Builder(); - for (Schema schema : schemas) - { - if (schema != null) - { - for (Column column : schema) - { + for (Schema schema : schemas) { + if (schema != null) { + for (Column column : schema) { builder.add(column.name); } } @@ -48,8 +43,7 @@ public static Schema merge(Schema... schemas) * * @return A schema builder. */ - public static Builder builder() - { + public static Builder builder() { return new Builder(); } @@ -58,13 +52,11 @@ public static Builder builder() * * @param columns The column names. */ - public Schema(String... columns) - { + public Schema(String... columns) { columnsByIndex = new Column[columns.length]; columnsByName = new HashMap<>(); - for (int i = 0; i < columns.length; ++i) - { + for (int i = 0; i < columns.length; ++i) { columnsByIndex[i] = new Column(columns[i]); columnsByName.put(columns[i], i); } @@ -76,8 +68,7 @@ public Schema(String... columns) * @param values Values to put in the row, in column order. * @return A new row. */ - public Row createRow(Variant... values) - { + public Row createRow(Variant... values) { return createRow(Arrays.asList(values)); } @@ -87,14 +78,12 @@ public Row createRow(Variant... values) * @param values Values to put in the row, in column order. * @return A new row. */ - public Row createRow(Collection values) - { + public Row createRow(Collection values) { int count = Math.min(values.size(), size()); Row.Cell[] cells = new Row.Cell[count]; int column = 0; - for (Variant value : values) - { + for (Variant value : values) { cells[column] = new Row.Cell(columnsByIndex[column], value); ++column; } @@ -108,8 +97,7 @@ public Row createRow(Collection values) * @param builderFunction A function that sets fields using a builder. * @return A new row. */ - public Row createRow(Consumer builderFunction) - { + public Row createRow(Consumer builderFunction) { RowBuilder builder = rowBuilder(); builderFunction.accept(builder); @@ -121,8 +109,7 @@ public Row createRow(Consumer builderFunction) * * @return A new row builder. */ - public RowBuilder rowBuilder() - { + public RowBuilder rowBuilder() { return new RowBuilder(this, size()); } @@ -131,8 +118,7 @@ public RowBuilder rowBuilder() * * @return The number of columns. */ - public int size() - { + public int size() { return columnsByIndex.length; } @@ -142,10 +128,8 @@ public int size() * @param index The column index. * @return The column if the index is valid. */ - public Optional getColumn(int index) - { - if (index >= 0 && index < columnsByIndex.length) - { + public Optional getColumn(int index) { + if (index >= 0 && index < columnsByIndex.length) { return Optional.of(columnsByIndex[index]); } @@ -158,12 +142,10 @@ public Optional getColumn(int index) * @param name The column name. * @return The column if it exists. */ - public Optional getColumn(String name) - { + public Optional getColumn(String name) { Integer index = columnsByName.get(name); - if (index != null) - { + if (index != null) { return Optional.of(columnsByIndex[index]); } @@ -171,23 +153,20 @@ public Optional getColumn(String name) } @Override - public Iterator iterator() - { + public Iterator iterator() { return new ArrayIterator<>(columnsByIndex); } /** * Creates schemas incrementally. */ - public static class Builder - { + public static class Builder { private List columns; /** * Create a new empty schema builder. */ - public Builder() - { + public Builder() { columns = new ArrayList<>(); } @@ -198,10 +177,8 @@ public Builder() * @return The builder. * @throws DuplicateColumnException if duplicate column names are found. */ - public Builder add(String name) - { - if (columns.contains(name)) - { + public Builder add(String name) { + if (columns.contains(name)) { throw new DuplicateColumnException(name); } @@ -215,8 +192,7 @@ public Builder add(String name) * * @return The new schema. */ - public Schema build() - { + public Schema build() { return new Schema(columns.toArray(new String[columns.size()])); } } @@ -224,13 +200,11 @@ public Schema build() /** * Creates rows following a schema incrementally. */ - public static class RowBuilder - { + public static class RowBuilder { private final Schema schema; private final Row.Cell[] cells; - private RowBuilder(Schema schema, int size) - { + private RowBuilder(Schema schema, int size) { this.schema = schema; this.cells = new Row.Cell[size]; } @@ -239,14 +213,12 @@ private RowBuilder(Schema schema, int size) * Set the value of a column. * * @param columnName The name of the column to set. - * @param value The column value. + * @param value The column value. */ - public void set(String columnName, Variant value) - { + public void set(String columnName, Variant value) { Integer index = schema.columnsByName.get(columnName); - if (index == null) - { + if (index == null) { throw new IllegalArgumentException(); } @@ -257,12 +229,10 @@ public void set(String columnName, Variant value) * Set the value of a column. * * @param columnIndex The index of the column to set. - * @param value The column value. + * @param value The column value. */ - public void set(int columnIndex, Variant value) - { - if (columnIndex < 0 || columnIndex >= schema.columnsByIndex.length) - { + public void set(int columnIndex, Variant value) { + if (columnIndex < 0 || columnIndex >= schema.columnsByIndex.length) { throw new IndexOutOfBoundsException(); } @@ -274,8 +244,7 @@ public void set(int columnIndex, Variant value) * * @return The new row. */ - public Row build() - { + public Row build() { Row.Cell[] copy = new Row.Cell[cells.length]; System.arraycopy(cells, 0, copy, 0, cells.length); @@ -286,10 +255,8 @@ public Row build() /** * Exception thrown when duplicate column names are attempted to be added to a schema. */ - public static class DuplicateColumnException extends RuntimeException - { - public DuplicateColumnException(String column) - { + public static class DuplicateColumnException extends RuntimeException { + public DuplicateColumnException(String column) { super("The column '" + column + "' already exists."); } } diff --git a/src/main/java/com/widen/tabitha/Utils.java b/src/main/java/com/widen/tabitha/Utils.java index cca350b..907e597 100644 --- a/src/main/java/com/widen/tabitha/Utils.java +++ b/src/main/java/com/widen/tabitha/Utils.java @@ -7,24 +7,21 @@ /** * Provides various supporting utility methods used within Tabitha. */ -public class Utils -{ +public class Utils { /** * Apply a function to an array and return a new array with the transformed values. * - * @param array The array to map. + * @param array The array to map. * @param function The function to apply. - * @param The item type of the original array. - * @param The item type of the new array. + * @param The item type of the original array. + * @param The item type of the new array. * @return The new array. */ - public static R[] mapArray(T[] array, Class type, Function function) - { + public static R[] mapArray(T[] array, Class type, Function function) { @SuppressWarnings("unchecked") R[] mapped = (R[]) Array.newInstance(type, array.length); - for (int i = 0; i < array.length; ++i) - { + for (int i = 0; i < array.length; ++i) { mapped[i] = function.apply(array[i]); } @@ -36,29 +33,24 @@ public static R[] mapArray(T[] array, Class type, Function funct * * @param iterator The iterator to map. * @param function The function to apply. - * @param The item type of the original iterator. - * @param The item type of the new iterator. + * @param The item type of the original iterator. + * @param The item type of the new iterator. * @return The new iterator. */ - public static Iterator mapIterator(Iterator iterator, Function function) - { - return new Iterator() - { + public static Iterator mapIterator(Iterator iterator, Function function) { + return new Iterator() { @Override - public boolean hasNext() - { + public boolean hasNext() { return iterator.hasNext(); } @Override - public R next() - { + public R next() { return function.apply(iterator.next()); } @Override - public void remove() - { + public void remove() { iterator.remove(); } }; @@ -69,12 +61,11 @@ public void remove() * * @param iterable The iterable to map. * @param function The function to apply. - * @param The item type of the original iterator. - * @param The item type of the new iterator. + * @param The item type of the original iterator. + * @param The item type of the new iterator. * @return The new iterable. */ - public static Iterable mapIterable(Iterable iterable, Function function) - { + public static Iterable mapIterable(Iterable iterable, Function function) { return () -> mapIterator(iterable.iterator(), function); } } diff --git a/src/main/java/com/widen/tabitha/Variant.java b/src/main/java/com/widen/tabitha/Variant.java index 3fd7e47..4fbdc31 100644 --- a/src/main/java/com/widen/tabitha/Variant.java +++ b/src/main/java/com/widen/tabitha/Variant.java @@ -7,16 +7,14 @@ *

* A variant can either be a {@link Bool}, a {@link String}, an {@link Int}, a {@link Float}, or {@link #NONE}. */ -public abstract class Variant -{ +public abstract class Variant { /** * Create a new boolean variant. * * @param value The boolean value. * @return The new variant. */ - public static Variant of(boolean value) - { + public static Variant of(boolean value) { // Use static objects already initialized to save memory. return value ? Bool.TRUE : Bool.FALSE; } @@ -27,10 +25,8 @@ public static Variant of(boolean value) * @param value The string value. * @return The new variant. */ - public static Variant of(java.lang.String value) - { - if (value == null) - { + public static Variant of(java.lang.String value) { + if (value == null) { return NONE; } @@ -43,8 +39,7 @@ public static Variant of(java.lang.String value) * @param value The integer value. * @return The new variant. */ - public static Variant of(long value) - { + public static Variant of(long value) { return new Int(value); } @@ -54,8 +49,7 @@ public static Variant of(long value) * @param value The floating-point value. * @return The new variant. */ - public static Variant of(double value) - { + public static Variant of(double value) { return new Float(value); } @@ -64,8 +58,7 @@ public static Variant of(double value) * * @return True if the variant is equal to {@link #NONE}, otherwise false. */ - public boolean isNone() - { + public boolean isNone() { return false; } @@ -74,8 +67,7 @@ public boolean isNone() * * @return The string value, or empty if this is not a string variant. */ - public Optional getString() - { + public Optional getString() { return Optional.empty(); } @@ -84,8 +76,7 @@ public Optional getString() * * @return The boolean value, or empty if this is not a boolean variant. */ - public Optional getBoolean() - { + public Optional getBoolean() { return Optional.empty(); } @@ -94,8 +85,7 @@ public Optional getBoolean() * * @return The integer value, or empty if this is not an integer variant. */ - public Optional getInteger() - { + public Optional getInteger() { return Optional.empty(); } @@ -104,30 +94,25 @@ public Optional getInteger() * * @return The float value, or empty if this is not a float variant. */ - public Optional getFloat() - { + public Optional getFloat() { return Optional.empty(); } // Private to prevent extending with unbounded variant types. - private Variant() - { + private Variant() { } /** * A variant that represents an empty value. */ - public static final Variant NONE = new Variant() - { + public static final Variant NONE = new Variant() { @Override - public boolean isNone() - { + public boolean isNone() { return true; } @Override - public java.lang.String toString() - { + public java.lang.String toString() { return ""; } }; @@ -135,8 +120,7 @@ public java.lang.String toString() /** * A variant representing a boolean true or false value. */ - public static final class Bool extends Variant - { + public static final class Bool extends Variant { private final boolean value; /** @@ -150,38 +134,31 @@ public static final class Bool extends Variant public static final Bool FALSE = new Bool(false); // Private to prevent more than two instances from existing. - private Bool(boolean value) - { + private Bool(boolean value) { this.value = value; } @Override - public Optional getBoolean() - { + public Optional getBoolean() { return Optional.of(value); } @Override - public java.lang.String toString() - { + public java.lang.String toString() { return Boolean.toString(value); } @Override - public boolean equals(Object other) - { - if (other == this) - { + public boolean equals(Object other) { + if (other == this) { return true; } - if (other instanceof Boolean) - { + if (other instanceof Boolean) { return value == (Boolean) other; } - if (other instanceof Bool) - { + if (other instanceof Bool) { return value == ((Bool) other).value; } @@ -192,8 +169,7 @@ public boolean equals(Object other) /** * A variant containing a string. */ - public static final class String extends Variant - { + public static final class String extends Variant { private final java.lang.String value; /** @@ -201,33 +177,27 @@ public static final class String extends Variant * * @param value The string value. */ - public String(java.lang.String value) - { + public String(java.lang.String value) { this.value = value; } @Override - public Optional getString() - { + public Optional getString() { return Optional.of(value); } @Override - public java.lang.String toString() - { + public java.lang.String toString() { return value; } @Override - public boolean equals(Object other) - { - if (value.equals(other)) - { + public boolean equals(Object other) { + if (value.equals(other)) { return true; } - if (other instanceof String) - { + if (other instanceof String) { return value.equals(((String) other).value); } @@ -238,8 +208,7 @@ public boolean equals(Object other) /** * A variant containing an integer. */ - public static final class Int extends Variant - { + public static final class Int extends Variant { private final long value; /** @@ -247,38 +216,31 @@ public static final class Int extends Variant * * @param value The integer value. */ - public Int(long value) - { + public Int(long value) { this.value = value; } @Override - public Optional getInteger() - { + public Optional getInteger() { return Optional.of(value); } @Override - public java.lang.String toString() - { + public java.lang.String toString() { return Long.toString(value); } @Override - public boolean equals(Object other) - { - if (other == this) - { + public boolean equals(Object other) { + if (other == this) { return true; } - if (other instanceof Number) - { + if (other instanceof Number) { return value == ((Number) other).longValue(); } - if (other instanceof Int) - { + if (other instanceof Int) { return value == ((Int) other).value; } @@ -289,8 +251,7 @@ public boolean equals(Object other) /** * A variant containing a floating-point number. Stored as a double-width float. */ - public static final class Float extends Variant - { + public static final class Float extends Variant { private final double value; /** @@ -298,38 +259,31 @@ public static final class Float extends Variant * * @param value The float value. */ - public Float(double value) - { + public Float(double value) { this.value = value; } @Override - public Optional getFloat() - { + public Optional getFloat() { return Optional.of(value); } @Override - public java.lang.String toString() - { + public java.lang.String toString() { return Double.toString(value); } @Override - public boolean equals(Object other) - { - if (other == this) - { + public boolean equals(Object other) { + if (other == this) { return true; } - if (other instanceof Number) - { + if (other instanceof Number) { return value == ((Number) other).doubleValue(); } - if (other instanceof Float) - { + if (other instanceof Float) { return value == ((Float) other).value; } diff --git a/src/main/java/com/widen/tabitha/collections/BoundedQueue.java b/src/main/java/com/widen/tabitha/collections/BoundedQueue.java index 3257434..dd7c736 100644 --- a/src/main/java/com/widen/tabitha/collections/BoundedQueue.java +++ b/src/main/java/com/widen/tabitha/collections/BoundedQueue.java @@ -13,8 +13,7 @@ *

* This queue uses internal synchronization and is fully thread-safe. */ -public class BoundedQueue implements Closeable -{ +public class BoundedQueue implements Closeable { private final CircularFifoQueue queue; private final AtomicBoolean closed; private final Lock lock; @@ -26,8 +25,7 @@ public class BoundedQueue implements Closeable * * @param capacity The queue capacity. */ - public BoundedQueue(int capacity) - { + public BoundedQueue(int capacity) { queue = new CircularFifoQueue<>(capacity); closed = new AtomicBoolean(); lock = new ReentrantLock(); @@ -40,8 +38,7 @@ public BoundedQueue(int capacity) * * @return True if {@link #close} has been called. */ - public boolean isClosed() - { + public boolean isClosed() { return closed.get(); } @@ -53,23 +50,18 @@ public boolean isClosed() * @param item The item to enqueue. * @return True if the item was added, false if the queue is closed. */ - public boolean enqueue(T item) - { - if (isClosed()) - { + public boolean enqueue(T item) { + if (isClosed()) { return false; } lock.lock(); - try - { - while (queue.isAtFullCapacity()) - { + try { + while (queue.isAtFullCapacity()) { canEnqueue.awaitUninterruptibly(); - if (isClosed()) - { + if (isClosed()) { return false; } } @@ -77,9 +69,7 @@ public boolean enqueue(T item) queue.add(item); canDequeue.signal(); return true; - } - finally - { + } finally { lock.unlock(); } } @@ -91,16 +81,12 @@ public boolean enqueue(T item) * * @return The removed item, or null if the queue is empty and closed. */ - public T dequeue() - { + public T dequeue() { lock.lock(); - try - { - while (queue.isEmpty()) - { - if (isClosed()) - { + try { + while (queue.isEmpty()) { + if (isClosed()) { return null; } @@ -109,10 +95,9 @@ public T dequeue() T item = queue.remove(); canEnqueue.signal(); + return item; - } - finally - { + } finally { lock.unlock(); } } @@ -120,16 +105,12 @@ public T dequeue() /** * Clear all items from the queue. */ - public void clear() - { + public void clear() { lock.lock(); - try - { + try { queue.clear(); - } - finally - { + } finally { lock.unlock(); } } @@ -138,19 +119,14 @@ public void clear() * Close the queue, preventing additional items from being added. */ @Override - public void close() - { - if (!closed.getAndSet(true)) - { + public void close() { + if (!closed.getAndSet(true)) { lock.lock(); - try - { + try { canEnqueue.signalAll(); canDequeue.signalAll(); - } - finally - { + } finally { lock.unlock(); } } diff --git a/src/main/java/com/widen/tabitha/collections/RingBuffer.java b/src/main/java/com/widen/tabitha/collections/RingBuffer.java index e6d740d..4309553 100644 --- a/src/main/java/com/widen/tabitha/collections/RingBuffer.java +++ b/src/main/java/com/widen/tabitha/collections/RingBuffer.java @@ -7,8 +7,7 @@ */ // Custom implementation, because none of the collections out there had the memory and performance optimizations that // I knew would give the best results for DataFrame. -public class RingBuffer extends AbstractCollection implements Collection -{ +public class RingBuffer extends AbstractCollection implements Collection { private static final int DEFAULT_INITIAL_CAPACITY = 32; private Object[] buffer; @@ -18,8 +17,7 @@ public class RingBuffer extends AbstractCollection implements Collection get(int index) - { - if (index >= size || index < 0) - { + public Optional get(int index) { + if (index >= size || index < 0) { return Optional.empty(); } @@ -85,22 +77,17 @@ public Optional get(int index) * @param index The element index. * @return True if the element was removed. */ - public boolean remove(int index) - { - if (index >= size || index < 0) - { + public boolean remove(int index) { + if (index >= size || index < 0) { return false; } int offset = wrappingOffset(index); - if (offset < head) - { + if (offset < head) { int tail = wrappingOffset(size - 1); System.arraycopy(buffer, offset + 1, buffer, offset, tail - offset); - } - else - { + } else { System.arraycopy(buffer, head, buffer, head + 1, index + 1); --head; } @@ -114,10 +101,8 @@ public boolean remove(int index) * * @return The element, or empty if the buffer is empty. */ - public Optional front() - { - if (size == 0) - { + public Optional front() { + if (size == 0) { return Optional.empty(); } @@ -131,10 +116,8 @@ public Optional front() * * @return The element, or empty if the buffer is empty. */ - public Optional back() - { - if (size == 0) - { + public Optional back() { + if (size == 0) { return Optional.empty(); } @@ -149,12 +132,10 @@ public Optional back() * * @param element The element to push. */ - public void pushFront(E element) - { + public void pushFront(E element) { Objects.requireNonNull(element); - if (size == buffer.length) - { + if (size == buffer.length) { resize(buffer.length * 2); } @@ -168,12 +149,10 @@ public void pushFront(E element) * * @param element The element to push. */ - public void pushBack(E element) - { + public void pushBack(E element) { Objects.requireNonNull(element); - if (size == buffer.length) - { + if (size == buffer.length) { resize(buffer.length * 2); } @@ -186,10 +165,8 @@ public void pushBack(E element) * * @return The element, or empty if the buffer is empty. */ - public Optional popFront() - { - if (size == 0) - { + public Optional popFront() { + if (size == 0) { return Optional.empty(); } @@ -206,10 +183,8 @@ public Optional popFront() * * @return The element, or empty if the buffer is empty. */ - public Optional popBack() - { - if (size == 0) - { + public Optional popBack() { + if (size == 0) { return Optional.empty(); } @@ -222,43 +197,36 @@ public Optional popBack() } @Override - public void clear() - { - while (size > 0) - { + public void clear() { + while (size > 0) { buffer[wrappingOffset(size - 1)] = null; --size; } } @Override - public Object[] toArray() - { + public Object[] toArray() { Object[] dest = new Object[size]; return toArray(dest); } @Override - public T[] toArray(T[] array) - { + public T[] toArray(T[] array) { Object[] dest = array; // If the given array is not large enough, allocate a new one. - if (dest.length < size) - { + if (dest.length < size) { dest = new Object[size]; } // Current buffer is wrapped, copy head segment first and then the tail segment. - if (head + size > buffer.length) - { + if (head + size > buffer.length) { int headSize = buffer.length - head; System.arraycopy(buffer, head, dest, 0, headSize); System.arraycopy(buffer, 0, dest, headSize, size - headSize); } // Buffer is contiguous, copy in one step. - else - { + else { System.arraycopy(buffer, head, dest, 0, size); } @@ -266,22 +234,18 @@ public T[] toArray(T[] array) } @Override - public Iterator iterator() - { - return new Iterator() - { + public Iterator iterator() { + return new Iterator() { private int nextIndex = 0; private int lastIndex = -1; @Override - public boolean hasNext() - { + public boolean hasNext() { return nextIndex < size; } @Override - public E next() - { + public E next() { lastIndex = nextIndex; ++nextIndex; @@ -289,15 +253,12 @@ public E next() } @Override - public void remove() - { - if (lastIndex < 0) - { + public void remove() { + if (lastIndex < 0) { throw new IllegalStateException(); } - if (!RingBuffer.this.remove(lastIndex)) - { + if (!RingBuffer.this.remove(lastIndex)) { throw new IllegalStateException(); } @@ -307,33 +268,26 @@ public void remove() }; } - private int wrappingOffset(int index) - { + private int wrappingOffset(int index) { int offset = head + index; - if (offset >= buffer.length) - { + if (offset >= buffer.length) { offset -= buffer.length; - } - else if (offset < 0) - { + } else if (offset < 0) { offset += buffer.length; } return offset; } - private E getAtOffset(int offset) - { + private E getAtOffset(int offset) { @SuppressWarnings("unchecked") E element = (E) buffer[offset]; return element; } - private void resize(int capacity) - { - if (capacity > buffer.length) - { + private void resize(int capacity) { + if (capacity > buffer.length) { // Create a new array with double the current capacity. Object[] dest = new Object[capacity]; diff --git a/src/main/java/com/widen/tabitha/formats/DelimitedRowReader.java b/src/main/java/com/widen/tabitha/formats/DelimitedRowReader.java index 9d2dff5..4f9aa57 100644 --- a/src/main/java/com/widen/tabitha/formats/DelimitedRowReader.java +++ b/src/main/java/com/widen/tabitha/formats/DelimitedRowReader.java @@ -14,18 +14,15 @@ /** * Reads a delimiter-separated text file into rows of values. */ -public class DelimitedRowReader implements RowReader -{ +public class DelimitedRowReader implements RowReader { private CSVReader reader; private Schema schema; - public DelimitedRowReader(InputStream inputStream, DelimitedTextFormat format) - { + public DelimitedRowReader(InputStream inputStream, DelimitedTextFormat format) { this(new InputStreamReader(inputStream, StandardCharsets.UTF_8), format); } - public DelimitedRowReader(Reader reader, DelimitedTextFormat format) - { + public DelimitedRowReader(Reader reader, DelimitedTextFormat format) { this.reader = new CSVReader( reader, format.getDelimiter(), @@ -37,16 +34,13 @@ public DelimitedRowReader(Reader reader, DelimitedTextFormat format) } @Override - public Optional read() throws IOException - { - if (schema == null) - { + public Optional read() throws IOException { + if (schema == null) { readHeaders(); } String[] columns = reader.readNext(); - if (columns == null) - { + if (columns == null) { return Optional.empty(); } @@ -55,23 +49,19 @@ public Optional read() throws IOException return Optional.of(schema.createRow(values)); } - private void readHeaders() throws IOException - { + private void readHeaders() throws IOException { String[] columns = reader.readNext(); Schema.Builder builder = new Schema.Builder(); - for (String column : columns) - { + for (String column : columns) { builder.add(column); } schema = builder.build(); } - private Variant asVariant(String value) - { - if (StringUtils.isNotBlank(value)) - { + private Variant asVariant(String value) { + if (StringUtils.isNotBlank(value)) { return new Variant.String(value); } diff --git a/src/main/java/com/widen/tabitha/formats/DelimitedRowWriter.java b/src/main/java/com/widen/tabitha/formats/DelimitedRowWriter.java index 58e6c02..33f889d 100644 --- a/src/main/java/com/widen/tabitha/formats/DelimitedRowWriter.java +++ b/src/main/java/com/widen/tabitha/formats/DelimitedRowWriter.java @@ -15,26 +15,21 @@ /** * Writes rows of values to a delimiter-separated text file. */ -public class DelimitedRowWriter implements RowWriter -{ +public class DelimitedRowWriter implements RowWriter { private CSVWriter writer; private boolean headersWritten = false; - public DelimitedRowWriter(OutputStream outputStream, DelimitedTextFormat format) - { + public DelimitedRowWriter(OutputStream outputStream, DelimitedTextFormat format) { this(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), format); } - public DelimitedRowWriter(Writer writer, DelimitedTextFormat format) - { + public DelimitedRowWriter(Writer writer, DelimitedTextFormat format) { this.writer = new CSVWriter(writer, format.getDelimiter(), format.getQuoteCharacter(), format.getEscapeCharacter()); } @Override - public void write(Row row) throws IOException - { - if (!headersWritten) - { + public void write(Row row) throws IOException { + if (!headersWritten) { writer.writeNext(Utils.mapArray(row.columns(), String.class, column -> column.name)); headersWritten = true; } @@ -42,8 +37,7 @@ public void write(Row row) throws IOException String[] cells = Utils.mapArray(row.values(), String.class, Variant::toString); int index = 0; - for (Row.Cell cell : row) - { + for (Row.Cell cell : row) { cells[index] = cell.value.toString(); ++index; } diff --git a/src/main/java/com/widen/tabitha/formats/DelimitedTextFormat.java b/src/main/java/com/widen/tabitha/formats/DelimitedTextFormat.java index bf54a0b..6f2cda3 100644 --- a/src/main/java/com/widen/tabitha/formats/DelimitedTextFormat.java +++ b/src/main/java/com/widen/tabitha/formats/DelimitedTextFormat.java @@ -3,8 +3,7 @@ /** * Format options for a delimiter-separated text file. */ -public class DelimitedTextFormat -{ +public class DelimitedTextFormat { /** * Delimited text format for a CSV file. */ @@ -20,51 +19,42 @@ public class DelimitedTextFormat private final char escapeCharacter; private final boolean strictQuotes; - public DelimitedTextFormat(char delimiter, char quoteCharacter, char escapeCharacter, boolean strictQuotes) - { + public DelimitedTextFormat(char delimiter, char quoteCharacter, char escapeCharacter, boolean strictQuotes) { this.delimiter = delimiter; this.quoteCharacter = quoteCharacter; this.escapeCharacter = escapeCharacter; this.strictQuotes = strictQuotes; } - public char getDelimiter() - { + public char getDelimiter() { return delimiter; } - public char getQuoteCharacter() - { + public char getQuoteCharacter() { return quoteCharacter; } - public char getEscapeCharacter() - { + public char getEscapeCharacter() { return escapeCharacter; } - public boolean isStrictQuotes() - { + public boolean isStrictQuotes() { return strictQuotes; } - public DelimitedTextFormat withDelimiter(char delimiter) - { + public DelimitedTextFormat withDelimiter(char delimiter) { return new DelimitedTextFormat(delimiter, quoteCharacter, escapeCharacter, strictQuotes); } - public DelimitedTextFormat withQuoteCharacter(char quoteCharacter) - { + public DelimitedTextFormat withQuoteCharacter(char quoteCharacter) { return new DelimitedTextFormat(delimiter, quoteCharacter, escapeCharacter, strictQuotes); } - public DelimitedTextFormat withEscapeCharacter(char escapeCharacter) - { + public DelimitedTextFormat withEscapeCharacter(char escapeCharacter) { return new DelimitedTextFormat(delimiter, quoteCharacter, escapeCharacter, strictQuotes); } - public DelimitedTextFormat withStrictQuotes(boolean strictQuotes) - { + public DelimitedTextFormat withStrictQuotes(boolean strictQuotes) { return new DelimitedTextFormat(delimiter, quoteCharacter, escapeCharacter, strictQuotes); } } diff --git a/src/main/java/com/widen/tabitha/formats/ExcelRowReader.java b/src/main/java/com/widen/tabitha/formats/ExcelRowReader.java index 27f8ef5..58f1321 100644 --- a/src/main/java/com/widen/tabitha/formats/ExcelRowReader.java +++ b/src/main/java/com/widen/tabitha/formats/ExcelRowReader.java @@ -19,42 +19,34 @@ /** * Reads rows from an Excel workbook. */ -public class ExcelRowReader implements RowReader -{ +public class ExcelRowReader implements RowReader { private Workbook workbook; private Schema schema; private int rowIndex = 0; - public ExcelRowReader(File file) throws InvalidFormatException, IOException - { + public ExcelRowReader(File file) throws InvalidFormatException, IOException { this(WorkbookFactory.create(file)); } - public ExcelRowReader(InputStream inputStream) throws InvalidFormatException, IOException - { + public ExcelRowReader(InputStream inputStream) throws InvalidFormatException, IOException { this(WorkbookFactory.create(inputStream)); } - public ExcelRowReader(Workbook workbook) - { + public ExcelRowReader(Workbook workbook) { this.workbook = workbook; } @Override - public Optional read() throws IOException - { - if (schema == null) - { + public Optional read() throws IOException { + if (schema == null) { readHeader(); } org.apache.poi.ss.usermodel.Row row = nextRow(); - if (row != null) - { + if (row != null) { Variant[] values = new Variant[row.getLastCellNum()]; - for (int i = 0; i < row.getLastCellNum(); ++i) - { + for (int i = 0; i < row.getLastCellNum(); ++i) { values[i] = getCellValue(row.getCell(i)); } @@ -64,16 +56,13 @@ public Optional read() throws IOException return Optional.empty(); } - private void readHeader() - { + private void readHeader() { org.apache.poi.ss.usermodel.Row row = nextRow(); - if (row != null) - { + if (row != null) { Schema.Builder builder = new Schema.Builder(); - for (int i = 0; i < row.getLastCellNum(); ++i) - { + for (int i = 0; i < row.getLastCellNum(); ++i) { builder.add(getCellValue(row.getCell(i)).toString()); } @@ -81,12 +70,10 @@ private void readHeader() } } - private org.apache.poi.ss.usermodel.Row nextRow() - { + private org.apache.poi.ss.usermodel.Row nextRow() { Sheet sheet = workbook.getSheetAt(0); - if (rowIndex > sheet.getLastRowNum()) - { + if (rowIndex > sheet.getLastRowNum()) { return null; } @@ -96,26 +83,21 @@ private org.apache.poi.ss.usermodel.Row nextRow() return row; } - private Variant getCellValue(Cell cell) - { - if (cell == null) - { + private Variant getCellValue(Cell cell) { + if (cell == null) { return Variant.NONE; } - switch (cell.getCellTypeEnum()) - { + switch (cell.getCellTypeEnum()) { case STRING: String string = cell.getRichStringCellValue().getString(); - if (StringUtils.isNotBlank(string)) - { + if (StringUtils.isNotBlank(string)) { return new Variant.String(string); } return Variant.NONE; case NUMERIC: - if (DateUtil.isCellDateFormatted(cell)) - { + if (DateUtil.isCellDateFormatted(cell)) { Date dateVal = cell.getDateCellValue(); return new Variant.String(new SimpleDateFormat().format(dateVal)); } diff --git a/src/main/java/com/widen/tabitha/formats/ExcelRowWriter.java b/src/main/java/com/widen/tabitha/formats/ExcelRowWriter.java index 1737355..8cad86b 100644 --- a/src/main/java/com/widen/tabitha/formats/ExcelRowWriter.java +++ b/src/main/java/com/widen/tabitha/formats/ExcelRowWriter.java @@ -16,12 +16,11 @@ /** * Writes rows to an Excel spreadsheet file. Supports creating XLS and XLSX files. - * + *

* This writer writes rows into memory and flushes changes all at once when {@link #close()} is called. This writer * should be avoided in memory-constrained environments. */ -public class ExcelRowWriter implements RowWriter -{ +public class ExcelRowWriter implements RowWriter { private OutputStream output; private Workbook workbook; private Sheet sheet; @@ -33,56 +32,48 @@ public class ExcelRowWriter implements RowWriter * * @param output The output stream to write to. */ - public ExcelRowWriter(OutputStream output) - { + public ExcelRowWriter(OutputStream output) { this(output, false); } /** * Create a new Excel row writer. * - * @param output The output stream to write to. + * @param output The output stream to write to. * @param legacyFormat Whether the legacy XLS format should be used. */ - public ExcelRowWriter(OutputStream output, boolean legacyFormat) - { + public ExcelRowWriter(OutputStream output, boolean legacyFormat) { this(output, legacyFormat, null); } /** * Create a new Excel row writer. * - * @param output The output stream to write to. + * @param output The output stream to write to. * @param sheetName The name of the sheet to write to. */ - public ExcelRowWriter(OutputStream output, String sheetName) - { + public ExcelRowWriter(OutputStream output, String sheetName) { this(output, false, sheetName); } /** * Create a new Excel row writer. * - * @param output The output stream to write to. + * @param output The output stream to write to. * @param legacyFormat Whether the legacy XLS format should be used. - * @param sheetName The name of the sheet to write to. + * @param sheetName The name of the sheet to write to. */ - public ExcelRowWriter(OutputStream output, boolean legacyFormat, String sheetName) - { + public ExcelRowWriter(OutputStream output, boolean legacyFormat, String sheetName) { this.output = output; - if (legacyFormat) - { + if (legacyFormat) { workbook = new HSSFWorkbook(); - } - else - { + } else { workbook = new XSSFWorkbook(); } // Create the first sheet. - if (sheetName == null) - { + if (sheetName == null) { sheetName = "Sheet 1"; } createSheet(sheetName); @@ -93,23 +84,19 @@ public ExcelRowWriter(OutputStream output, boolean legacyFormat, String sheetNam * * @param name The name of the sheet. */ - public void createSheet(String name) - { + public void createSheet(String name) { sheet = workbook.createSheet(name); headersWritten = false; rowIndex = 0; } @Override - public void write(Row row) throws IOException - { - if (!headersWritten) - { + public void write(Row row) throws IOException { + if (!headersWritten) { org.apache.poi.ss.usermodel.Row workbookRow = sheet.createRow(rowIndex++); Column[] columns = row.columns(); - for (int column = 0; column < columns.length; ++column) - { + for (int column = 0; column < columns.length; ++column) { Cell workbookCell = workbookRow.createCell(column); workbookCell.setCellType(CellType.STRING); workbookCell.setCellValue(columns[column].name); @@ -121,32 +108,22 @@ public void write(Row row) throws IOException org.apache.poi.ss.usermodel.Row workbookRow = sheet.createRow(rowIndex++); int column = 0; - for (Row.Cell cell : row) - { + for (Row.Cell cell : row) { Variant value = cell.value; Cell workbookCell = workbookRow.createCell(column); - if (value.isNone()) - { + if (value.isNone()) { workbookCell.setCellType(CellType.BLANK); - } - else if (value.getInteger().isPresent()) - { + } else if (value.getInteger().isPresent()) { workbookCell.setCellType(CellType.NUMERIC); workbookCell.setCellValue(value.getInteger().get()); - } - else if (value.getFloat().isPresent()) - { + } else if (value.getFloat().isPresent()) { workbookCell.setCellType(CellType.NUMERIC); workbookCell.setCellValue(value.getFloat().get()); - } - else if (value.getBoolean().isPresent()) - { + } else if (value.getBoolean().isPresent()) { workbookCell.setCellType(CellType.BOOLEAN); workbookCell.setCellValue(value.getBoolean().get()); - } - else - { + } else { workbookCell.setCellType(CellType.STRING); workbookCell.setCellValue(value.toString()); } @@ -156,8 +133,7 @@ else if (value.getBoolean().isPresent()) } @Override - public void close() throws IOException - { + public void close() throws IOException { workbook.write(output); workbook.close(); } diff --git a/src/main/java/com/widen/tabitha/parallel/ProcessorExecutor.java b/src/main/java/com/widen/tabitha/parallel/ProcessorExecutor.java index 7bf1239..18b7233 100644 --- a/src/main/java/com/widen/tabitha/parallel/ProcessorExecutor.java +++ b/src/main/java/com/widen/tabitha/parallel/ProcessorExecutor.java @@ -9,8 +9,7 @@ /** * Executes a row processor in an efficient multi-threaded manner. */ -public class ProcessorExecutor -{ +public class ProcessorExecutor { private static final int DEFAULT_BUFFER_SIZE = 4096; private final Stack threadPool; @@ -23,19 +22,17 @@ public class ProcessorExecutor * @param rowProcessor Processor to process rows with. * @return The new executor. */ - public static ProcessorExecutor createDefault(RowProcessor rowProcessor) - { + public static ProcessorExecutor createDefault(RowProcessor rowProcessor) { return new ProcessorExecutor(DEFAULT_BUFFER_SIZE, rowProcessor); } /** * Create a new processor executor. * - * @param bufferSize Maximum number of rows to queue. + * @param bufferSize Maximum number of rows to queue. * @param rowProcessor Processor to process rows with. */ - public ProcessorExecutor(int bufferSize, RowProcessor rowProcessor) - { + public ProcessorExecutor(int bufferSize, RowProcessor rowProcessor) { threadPool = new Stack<>(); queue = new BoundedQueue<>(bufferSize); processor = rowProcessor; @@ -46,14 +43,12 @@ public ProcessorExecutor(int bufferSize, RowProcessor rowProcessor) * * @param rowReader Reader to read rows from. */ - public void execute(RowReader rowReader) - { + public void execute(RowReader rowReader) { queue.clear(); // Spawn two consumer threads per processor. int count = Runtime.getRuntime().availableProcessors() * 2; - for (int i = 0; i < count; ++i) - { + for (int i = 0; i < count; ++i) { Thread thread = new Thread(this::consumer); thread.start(); @@ -75,8 +70,7 @@ public void execute(RowReader rowReader) * * @param rowReader Row reader to read from. */ - private void producer(RowReader rowReader) - { + private void producer(RowReader rowReader) { // Block the current thread, filling the queue up as needed until we reach the end of the reader. rowReader.forEach(queue::enqueue); @@ -87,14 +81,11 @@ private void producer(RowReader rowReader) /** * Consume rows from the queue and process them. */ - private void consumer() - { - while (true) - { + private void consumer() { + while (true) { Row row = queue.dequeue(); - if (row == null) - { + if (row == null) { // Queue is closed, shut down. break; } @@ -106,21 +97,15 @@ private void consumer() /** * Shutdown all consumer threads in the pool. */ - private void shutdown() - { + private void shutdown() { // Wait for all threads to terminate. - while (!threadPool.isEmpty()) - { + while (!threadPool.isEmpty()) { Thread thread = threadPool.pop(); - while (true) - { - try - { + while (true) { + try { thread.join(); break; - } - catch (InterruptedException e) - { + } catch (InterruptedException e) { // Failed to join, retry. } } diff --git a/src/main/java/com/widen/tabitha/parallel/RowProcessor.java b/src/main/java/com/widen/tabitha/parallel/RowProcessor.java index b20a73b..5661ebc 100644 --- a/src/main/java/com/widen/tabitha/parallel/RowProcessor.java +++ b/src/main/java/com/widen/tabitha/parallel/RowProcessor.java @@ -6,11 +6,10 @@ * Processes a stream of rows. */ @FunctionalInterface -public interface RowProcessor -{ +public interface RowProcessor { /** * Process a single row. - * + *

* This method is required to be thread-safe, as it may get called concurrently from multiple threads at once. * * @param row The row to process. @@ -20,12 +19,12 @@ public interface RowProcessor /** * Method called when the processor begins processing a data set. */ - default void onStart() - {} + default void onStart() { + } /** * Method called when the processor reaches the end of a data set. */ - default void onComplete() - {} + default void onComplete() { + } }