This is an automated email from the git hooks/post-receive script. New commit to branch feature/3790_export_to_reader_or_input_steam in repository nuiton-csv. See http://git.nuiton.org/nuiton-csv.git commit 6b594380db15abdcb0139de7fdd0a0ae83d2cbb2 Author: Tony CHEMIT <chemit@codelutin.com> Date: Mon Dec 7 22:46:09 2015 +0100 Add Export.exportToReader and Export.exportToInputStream method (See #3790) --- src/main/java/org/nuiton/csv/Export.java | 288 ++++++++++++++++++++++++++++--- 1 file changed, 261 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/nuiton/csv/Export.java b/src/main/java/org/nuiton/csv/Export.java index 7d6657d..6d30ea6 100644 --- a/src/main/java/org/nuiton/csv/Export.java +++ b/src/main/java/org/nuiton/csv/Export.java @@ -21,6 +21,7 @@ */ package org.nuiton.csv; +import com.google.common.collect.ImmutableSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.util.StringUtil; @@ -29,11 +30,14 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.Reader; import java.io.Writer; import java.nio.charset.Charset; import java.util.Collection; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -80,6 +84,8 @@ public class Export<E> { */ protected final String separator; + protected Iterable<ExportableColumn<E, Object>> columnsForExport; + public static <E> Export<E> newExport(ExportModel<E> model, Iterable<E> data) { return new Export<E>(model, data); @@ -177,6 +183,30 @@ public class Export<E> { return exporter.toString(charset, writeHeader); } + public static <E> Reader exportToReader(ExportModel<E> model, + Iterable<E> data, + Charset charset) throws Exception { + + return exportToReader(model, data, charset, true); + } + + public static <E> Reader exportToReader(ExportModel<E> model, + Iterable<E> data, + Charset charset, + boolean writeHeader) throws Exception { + Export<E> exporter = newExport(model, data); + return exporter.newExportToReader(charset, writeHeader); + } + + public static <E> InputStream exportToInputStream(ExportModel<E> model, Iterable<E> data) { + return exportToInputStream(model, data, true); + } + + public static <E> InputStream exportToInputStream(ExportModel<E> model, Iterable<E> data, boolean writeHeader) { + Export<E> exporter = newExport(model, data); + return exporter.newExportToInputStream(writeHeader); + } + protected Export(ExportModel<E> model, Iterable<E> data) { this.model = model; this.data = data; @@ -194,24 +224,16 @@ public class Export<E> { writeHeader(writer); } - // obtain export columns - Iterable<ExportableColumn<E, Object>> columns = - model.getColumnsForExport(); - for (E row : data) { // write the row for this data - writeRow(writer, columns, row); + writeRow(writer, row); } } protected void writeHeader(Writer writer) throws IOException { - List<String> headerNames = new LinkedList<String>(); - for (ExportableColumn<E, ?> column : model.getColumnsForExport()) { - headerNames.add(column.getHeaderName()); - } - String headersLine = StringUtil.join(headerNames, separator, true); + String headersLine = getHeader(); writer.write(headersLine); writer.write('\n'); if (log.isDebugEnabled()) { @@ -222,23 +244,8 @@ public class Export<E> { } } - protected void writeRow(Writer writer, - Iterable<ExportableColumn<E, Object>> columns, - E row) throws Exception { - - List<String> formattedCells = new LinkedList<String>(); - for (ExportableColumn<E, Object> column : columns) { - Object cell = column.getValue(row); - String formattedCell = column.formatValue(cell); - if (formattedCell == null) { - throw new NullPointerException( - "column for header " + column.getHeaderName() + - " returned a null value." + column.toString()); - } - formattedCell = StringUtil.escapeCsvValue(formattedCell, separator); - formattedCells.add(formattedCell); - } - String formattedRow = StringUtil.join(formattedCells, separator, true); + protected void writeRow(Writer writer, E row) throws Exception { + String formattedRow = getRow(row); writer.write(formattedRow); writer.write('\n'); } @@ -294,4 +301,231 @@ public class Export<E> { return result; } + protected String getHeader() { + List<String> headerNames = new LinkedList<>(); + for (ExportableColumn<E, ?> column : getColumnsForExport()) { + headerNames.add(column.getHeaderName()); + } + return getFormattedRow(headerNames); + } + + protected String getRow(E row) throws Exception { + List<String> formattedCells = new LinkedList<>(); + for (ExportableColumn<E, Object> column : getColumnsForExport()) { + Object cell = column.getValue(row); + String formattedCell = column.formatValue(cell); + if (formattedCell == null) { + throw new NullPointerException( + "column for header " + column.getHeaderName() + + " returned a null value." + column.toString()); + } + formattedCell = StringUtil.escapeCsvValue(formattedCell, separator); + formattedCells.add(formattedCell); + } + return getFormattedRow(formattedCells); + } + + protected Iterable<ExportableColumn<E, Object>> getColumnsForExport() { + if (columnsForExport == null) { + columnsForExport = ImmutableSet.copyOf(model.getColumnsForExport()); + } + return columnsForExport; + } + + protected String getFormattedRow(List<String> formattedCells) { + return StringUtil.join(formattedCells, separator, true); + } + + protected Reader newExportToReader(Charset charset, boolean writeHeader) { + return new ExportToReader(charset, writeHeader); + } + + protected InputStream newExportToInputStream(boolean writeHeader) { + return new ExportToInputStream(writeHeader); + } + + /** + * Created on 07/12/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ + protected class ExportToInputStream extends InputStream { + + private final ToIoContext toIoContext; + + protected ExportToInputStream(boolean writeHeader) { + this.toIoContext = new ToIoContext(data.iterator(), writeHeader); + } + + @Override + public int read() throws IOException { + + String currentRow = toIoContext.readCurrentRow(); + + int result; + if (currentRow == null) { + + // end of stream + result = -1; + + } else { + + int length = currentRow.length(); + + result = currentRow.charAt(0); + + toIoContext.resizeCurrentRow(1, length == 1); + + } + + return result; + + } + + @Override + public void close() throws IOException { + // nothing to do + } + + } + + /** + * Created on 07/12/15. + * + * @author Tony Chemit - chemit@codelutin.com + */ + protected class ExportToReader extends Reader { + + protected final Charset charset; + + private final ToIoContext toIoContext; + + protected ExportToReader(Charset charset, boolean writeHeader) { + this.charset = charset; + this.toIoContext = new ToIoContext(data.iterator(), writeHeader); + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + + String currentRow = toIoContext.readCurrentRow(); + + int result; + if (currentRow == null) { + + // end of stream + result = -1; + + } else { + + int length = currentRow.length(); + if (length >= len) { + + // enough in this row to fill buffer + toIoContext.fillBufferAndResizeCurrentRow(cbuf, off, len, false); + result = len; + + } else { + + // fill with that we got + toIoContext.fillBufferAndResizeCurrentRow(cbuf, off, length, true); + + currentRow = toIoContext.currentRow; + + if (currentRow == null) { + + // no more stuff + result = length; + + } else { + + // ask for the rest + result = length + read(cbuf, off + length, len - length); + + } + + } + + } + + return result; + + } + + @Override + public void close() throws IOException { + // nothing to do + } + + } + + protected class ToIoContext { + + protected final Iterator<E> dataIterator; + + protected final boolean writeHeader; + + protected String firstRow; + + protected String currentRow; + + public ToIoContext(Iterator<E> dataIterator, boolean writeHeader) { + this.dataIterator = dataIterator; + this.writeHeader = writeHeader; + } + + protected String readCurrentRow() { + + if (firstRow == null) { + if (writeHeader) { + firstRow = getHeader() + '\n'; + currentRow = firstRow; + } else { + readNextRow(dataIterator); + firstRow = currentRow; + } + } + + return currentRow; + + } + + protected void readNextRow(Iterator<E> iterator) { + + currentRow = null; + if (iterator.hasNext()) { + E row = iterator.next(); + try { + currentRow = getRow(row) + '\n'; + } catch (Exception e) { + throw new ImportRuntimeException("Could not obtain row", e); + } + } + + } + + protected void fillBufferAndResizeCurrentRow(char[] cbuf, int off, int len, boolean computeNext) { + + for (int i = 0; i < len; i++) { + char c = currentRow.charAt(i); + cbuf[i + off] = c; + } + resizeCurrentRow(len, computeNext); + + } + + protected void resizeCurrentRow(int len, boolean computeNext) { + + if (computeNext) { + readNextRow(dataIterator); + } else { + currentRow = currentRow.substring(len); + if (currentRow.isEmpty()) { + currentRow = null; + } + } + + } + + } } -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.