/*
* (c) Copyright 2007-2011 by Volker Bergmann. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted under the terms of the
* GNU General Public License.
*
* For redistributing this software or a derivative work under a license other
* than the GPL-compatible Free Software License as defined by the Free
* Software Foundation or approved by OSI, you must first obtain a commercial
* license to this software product from Volker Bergmann.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
* REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
* HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.databene.platform.csv;
import org.databene.model.data.ComplexTypeDescriptor;
import org.databene.model.data.ComponentDescriptor;
import org.databene.model.data.Entity;
import org.databene.benerator.consumer.TextFileExporter;
import org.databene.benerator.engine.DefaultBeneratorContext;
import org.databene.commons.ArrayFormat;
import org.databene.commons.ArrayUtil;
import org.databene.commons.BeanUtil;
import org.databene.commons.CollectionUtil;
import org.databene.commons.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
/**
* Exports Entities to a CSV file.
* The default line separator is CR LF according to RFC 4180.
* It can be set explicitly by <code>setLineSeparator()</code>.<br/>
* <br/>
* Created: 21.08.2007 21:16:59
* @author Volker Bergmann
*/
public class CSVEntityExporter extends TextFileExporter {
private static final Logger logger = LoggerFactory.getLogger(CSVEntityExporter.class);
// defaults --------------------------------------------------------------------------------------------------------
private static final String DEFAULT_LINE_SEPARATOR = "\r\n"; // as defined by RFC 4180
private static final String DEFAULT_URI = "export.csv";
// configuration attributes ----------------------------------------------------------------------------------------
private String[] columns;
private boolean headless;
private boolean endWithNewLine;
private char separator;
private boolean quoteEmpty;
// state attributes ------------------------------------------------------------------------------------------------
private boolean lfRequired;
// constructors ----------------------------------------------------------------------------------------------------
public CSVEntityExporter() {
this(DEFAULT_URI);
}
public CSVEntityExporter(String uri) {
this(uri, (String) null);
}
public CSVEntityExporter(String uri, String columnsSpec) {
this(uri, columnsSpec, DefaultBeneratorContext.getDefaultCellSeparator(), null, DEFAULT_LINE_SEPARATOR);
}
public CSVEntityExporter(String uri, String columnsSpec, char separator, String encoding, String lineSeparator) {
super(uri, encoding, lineSeparator);
if (columnsSpec != null)
setColumns(ArrayFormat.parse(columnsSpec, ",", String.class));
this.separator = separator;
this.quoteEmpty = true;
}
public CSVEntityExporter(ComplexTypeDescriptor descriptor) {
this(descriptor.getName() + ".csv", descriptor);
}
public CSVEntityExporter(String uri, ComplexTypeDescriptor descriptor) {
this(uri, descriptor, DefaultBeneratorContext.getDefaultCellSeparator(), null, DEFAULT_LINE_SEPARATOR);
}
public CSVEntityExporter(String uri, ComplexTypeDescriptor descriptor, char separator, String encoding, String lineSeparator) {
super(uri, encoding, lineSeparator);
Collection<ComponentDescriptor> componentDescriptors = descriptor.getComponents();
List<String> componentNames = BeanUtil.extractProperties(componentDescriptors, "name");
this.columns = CollectionUtil.toArray(componentNames, String.class);
this.endWithNewLine = false;
this.separator = separator;
}
// properties ------------------------------------------------------------------------------------------------------
public void setColumns(String[] columns) {
if (ArrayUtil.isEmpty(columns))
this.columns = null;
else {
this.columns = columns;
StringUtil.trimAll(this.columns);
}
}
public void setSeparator(char separator) {
this.separator = separator;
}
public boolean isHeadless() {
return headless;
}
public void setHeadless(boolean headless) {
this.headless = headless;
}
public boolean isEndWithNewLine() {
return endWithNewLine;
}
public void setEndWithNewLine(boolean endWithNewLine) {
this.endWithNewLine = endWithNewLine;
}
public boolean isQuoteEmpty() {
return quoteEmpty;
}
public void setQuoteEmpty(boolean quoteEmpty) {
this.quoteEmpty = quoteEmpty;
}
// Callback methods for parent class functionality -----------------------------------------------------------------
@Override
protected void startConsumingImpl(Object object) {
logger.debug("exporting {}", object);
if (!(object instanceof Entity))
throw new IllegalArgumentException("Expecting entity");
Entity entity = (Entity) object;
if (lfRequired)
println();
else
lfRequired = true;
for (int i = 0; i < columns.length; i++) {
if (i > 0)
printer.print(separator);
Object value = entity.getComponent(columns[i]);
String out;
if (value == null)
out = getNullString();
else {
out = plainConverter.convert(value);
if (out.length() == 0 && quoteEmpty)
out = "\"\"";
else if (out.indexOf(separator) >= 0)
out = '"' + out + '"';
}
printer.print(out);
}
}
@Override
protected void postInitPrinter(Object object) {
Entity entity = (Entity) object;
// determine columns from entity, if they have not been predefined
if (columns == null && entity != null)
columns = CollectionUtil.toArray(entity.getComponents().keySet());
printHeaderRow();
}
@Override
protected void preClosePrinter() {
if (endWithNewLine)
println();
}
// private helpers -------------------------------------------------------------------------------------------------
private void printHeaderRow() {
if (!wasAppended && !headless && columns != null) {
if (wasAppended && !endWithNewLine)
println();
for (int i = 0; i < columns.length; i++) {
if (i > 0)
printer.print(separator);
printer.print(columns[i]);
}
lfRequired = true;
} else {
lfRequired = (wasAppended && !endWithNewLine);
}
}
}