All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jasperreports.engine.export.JRCsvMetadataExporter Maven / Gradle / Ivy

There is a newer version: 6.21.2
Show newest version
/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2022 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see .
 */
package net.sf.jasperreports.engine.export;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.jasperreports.annotations.properties.Property;
import net.sf.jasperreports.annotations.properties.PropertyScope;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JRPrintText;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.util.JRStringUtil;
import net.sf.jasperreports.engine.util.JRStyledText;
import net.sf.jasperreports.export.CsvMetadataExporterConfiguration;
import net.sf.jasperreports.export.CsvMetadataReportConfiguration;
import net.sf.jasperreports.properties.PropertyConstants;


/**
 * Exports a JasperReports document to CSV format based on the metadata provided.
 * 

* The exporter allows users to specify which columns should be included in the CSV export, what other value than the default * should they contain and whether the values for some columns should be auto filled when they are empty or missing (e.g. value * for group columns) * * @author Narcis Marcu ([email protected]) */ public class JRCsvMetadataExporter extends JRAbstractCsvExporter { /** * Property specifying the name of the column that should appear in the CSV export. * It must be one of the values in {@link CsvMetadataReportConfiguration#getColumnNames()}, if provided. * * @see JRPropertiesUtil */ @Property( category = PropertyConstants.CATEGORY_EXPORT, scopes = {PropertyScope.TEXT_ELEMENT}, sinceVersion = PropertyConstants.VERSION_4_0_0 ) public static final String PROPERTY_COLUMN_NAME = JRPropertiesUtil.PROPERTY_PREFIX + "export.csv.column.name"; /** * Property that specifies whether the value associated with {@link #PROPERTY_COLUMN_NAME PROPERTY_COLUMN_NAME} should be repeated or not * when it is missing. *

* The property itself defaults to false. *

* * @see JRPropertiesUtil */ @Property( category = PropertyConstants.CATEGORY_EXPORT, defaultValue = PropertyConstants.BOOLEAN_FALSE, scopes = {PropertyScope.TEXT_ELEMENT}, sinceVersion = PropertyConstants.VERSION_4_0_0, valueType = Boolean.class ) public static final String PROPERTY_REPEAT_VALUE = JRPropertiesUtil.PROPERTY_PREFIX + "export.csv.repeat.value"; /** * Property that specifies what value to associate with {@link #PROPERTY_COLUMN_NAME PROPERTY_COLUMN_NAME}. *

* The property itself defaults to the text value of the report element that this property is assigned to. *

* * @see JRPropertiesUtil */ @Property( category = PropertyConstants.CATEGORY_EXPORT, scopes = {PropertyScope.TEXT_ELEMENT}, sinceVersion = PropertyConstants.VERSION_4_0_0 ) public static final String PROPERTY_DATA = JRPropertiesUtil.PROPERTY_PREFIX + "export.csv.data"; /** * */ protected List columnNames; boolean isFirstRow = true; protected class ExporterContext extends BaseExporterContext implements JRCsvExporterContext { } /** * @see #JRCsvMetadataExporter(JasperReportsContext) */ public JRCsvMetadataExporter() { this(DefaultJasperReportsContext.getInstance()); } /** * */ public JRCsvMetadataExporter(JasperReportsContext jasperReportsContext) { super(jasperReportsContext); exporterContext = new ExporterContext(); } @Override protected Class getConfigurationInterface() { return CsvMetadataExporterConfiguration.class; } @Override protected Class getItemConfigurationInterface() { return CsvMetadataReportConfiguration.class; } @Override @SuppressWarnings("deprecation") protected void ensureOutput() { if (exporterOutput == null) { exporterOutput = new net.sf.jasperreports.export.parameters.ParametersWriterExporterOutput( getJasperReportsContext(), getParameters(), getCurrentJasperPrint() ); } } @Override protected void exportPage(JRPrintPage page) throws IOException { List elements = page.getElements(); Map currentRow = new HashMap<>(); Map repeatedValues = new HashMap<>(); CsvMetadataReportConfiguration configuration = getCurrentItemConfiguration(); boolean hasDefinedColumns = columnNames != null; // if columns where passed in as property exportElements(elements, configuration, currentRow, repeatedValues, hasDefinedColumns); // write last row if (columnNames != null && columnNames.size() > 0) { // write header if it was not yet written if (isFirstRow && configuration.isWriteHeader()) { writeReportHeader(); isFirstRow = false; } writeCurrentRow(currentRow, repeatedValues); } JRExportProgressMonitor progressMonitor = configuration.getProgressMonitor(); if (progressMonitor != null) { progressMonitor.afterPageExport(); } } protected void exportElements( List elements, CsvMetadataReportConfiguration configuration, Map currentRow, Map repeatedValues, boolean hasDefinedColumns) throws IOException { for (int i = 0; i < elements.size(); ++i) { Object element = elements.get(i); if (element instanceof JRPrintText) { exportText((JRPrintText) element, configuration, currentRow, repeatedValues, hasDefinedColumns); } else if (element instanceof JRPrintFrame) { exportElements(((JRPrintFrame) element).getElements(), configuration, currentRow, repeatedValues, hasDefinedColumns); } } } protected void exportText( JRPrintText textElement, CsvMetadataReportConfiguration configuration, Map currentRow, Map repeatedValues, boolean hasDefinedColumns) throws IOException { String currentTextValue = null; if (textElement.getPropertiesMap().getPropertyNames().length > 0) { String currentColumnName = textElement.getPropertiesMap().getProperty(PROPERTY_COLUMN_NAME); String currentColumnData = textElement.getPropertiesMap().getProperty(PROPERTY_DATA); boolean repeatValue = getPropertiesUtil().getBooleanProperty(textElement, PROPERTY_REPEAT_VALUE, false); if (textElement.getPropertiesMap().containsProperty(PROPERTY_DATA)) { currentTextValue = currentColumnData; } else { JRStyledText styledText = getStyledText(textElement); if (styledText != null) { currentTextValue = styledText.getText(); } else { currentTextValue = ""; } } // when no columns are provided, build the column names list as they are retrieved from the report element property if (!hasDefinedColumns) { if (columnNames == null) { columnNames = new ArrayList<>(); } if (currentColumnName != null && currentColumnName.length() > 0 && !columnNames.contains(currentColumnName)) { columnNames.add(currentColumnName); } } if (columnNames.size() > 0) { if (columnNames.contains(currentColumnName) && !currentRow.containsKey(currentColumnName) && isColumnReadOnTime(currentRow, currentColumnName)) // the column is for export but was not read yet and comes in the expected order { currentRow.put(currentColumnName, currentTextValue); } else if ( (columnNames.contains(currentColumnName) && !currentRow.containsKey(currentColumnName) && !isColumnReadOnTime(currentRow, currentColumnName)) // the column is for export, was not read yet, but it is read after it should be || (columnNames.contains(currentColumnName) && currentRow.containsKey(currentColumnName)) ) // the column is for export and was already read { // write header if (isFirstRow && configuration.isWriteHeader()) { writeReportHeader(); } isFirstRow = false; writeCurrentRow(currentRow, repeatedValues); currentRow.clear(); currentRow.put(currentColumnName, currentTextValue); } // set auto fill columns if (repeatValue && currentColumnName != null && currentColumnName.length() > 0 && currentTextValue.length() > 0) { repeatedValues.put(currentColumnName, currentTextValue); } } } } @Override protected void initExport() { super.initExport(); } @Override protected void initReport() { super.initReport(); CsvMetadataReportConfiguration configuration = getCurrentItemConfiguration(); columnNames = JRStringUtil.split(configuration.getColumnNames(), ","); isFirstRow = true; } /** * Writes the delimiter-separated column names */ protected void writeReportHeader() throws IOException { StringBuilder rowBuilder = new StringBuilder(); for (int i = 0; i < columnNames.size(); i++) { rowBuilder.append(columnNames.get(i)); if (i < (columnNames.size()-1)) { rowBuilder.append(fieldDelimiter); } else { rowBuilder.append(recordDelimiter); } } if (rowBuilder.length() > 0) { writer.write(rowBuilder.toString()); } } /** * Writes the current row. *

* If the row is empty, nothing is written. If the are columns for auto fill (with valid data), they will be set on the current * row and the row will be written only if it was not originally empty. This prevents the export file from having rows just with auto filled data. *

* @param currentRow * @param repeatedValues * @throws IOException */ protected void writeCurrentRow(Map currentRow, Map repeatedValues) throws IOException { // FIXME: the rows that are incomplete (e.g. in case of a group, there are rows that contain only the group columns // because the report spanned over a new page and it contains only the values for the group columns, as header, and other information // that is not for export, like counts or totals) should not be written StringBuilder rowBuilder = new StringBuilder(); boolean isEmptyRow = true; for (int i = 0; i < columnNames.size(); i++) { String currentTextValue = currentRow.get(columnNames.get(i)); if (currentTextValue != null && currentTextValue.length() > 0) { isEmptyRow = false; rowBuilder.append(prepareText(currentTextValue)); } else { String repeatedValue = repeatedValues.get(columnNames.get(i)); if (repeatedValue != null && repeatedValue.length() > 0) { rowBuilder.append(prepareText(repeatedValue)); } } if (i < (columnNames.size()-1)) { rowBuilder.append(fieldDelimiter); } else { rowBuilder.append(recordDelimiter); } } if (!isEmptyRow) { writer.write(rowBuilder.toString()); } } /** * Compares the highest index of the currentRow's columns with the index of the column to be inserted * to determine if the current column is read in the proper order *

* @param currentRow * @param currentColumnName */ private boolean isColumnReadOnTime(Map currentRow, String currentColumnName) { int indexOfLastFilledColumn = -1; Set currentlyFilledColumns = currentRow.keySet(); for (String column: currentlyFilledColumns) { indexOfLastFilledColumn = Math.max(indexOfLastFilledColumn, columnNames.indexOf(column)); } return indexOfLastFilledColumn < columnNames.indexOf(currentColumnName); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy