/* * JasperReports - Free Java Reporting Library. * Copyright (C) 2001 - 2009 Jaspersoft Corporation. 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 <http://www.gnu.org/licenses/>. */ package net.sf.jasperreports.engine.data; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import jxl.Cell; import jxl.Sheet; import jxl.Workbook; import jxl.read.biff.BiffException; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRField; import net.sf.jasperreports.engine.JRRewindableDataSource; import net.sf.jasperreports.engine.JRRuntimeException; /** * This data source implementation reads an XLS stream. * <p> * The default naming convention is to name report fields COLUMN_x and map each column with the field found at index x * in each row (these indices start with 0). To avoid this situation, users can either specify a collection of column * names or set a flag to read the column names from the first row of the CSV file. * * @author Teodor Danciu (teodord@users.sourceforge.net) * @version $Id: JRCsvDataSource.java 3033 2009-08-27 11:46:22Z teodord $ */ public class JRXlsDataSource implements JRRewindableDataSource { private Workbook workbook = null; private DateFormat dateFormat = new SimpleDateFormat(); private NumberFormat numberFormat = new DecimalFormat(); private Map columnNames = new HashMap(); private boolean useFirstRowAsHeader = false; private int recordIndex = -1; private InputStream inputStream = null; private boolean closeWorkbook = false; /** * Creates a data source instance from a workbook. * @param workbook the workbook */ public JRXlsDataSource(Workbook workbook) { this.workbook = workbook; this.closeWorkbook = false; } /** * Creates a data source instance from an XLS data input stream. * @param is an input stream containing XLS data */ public JRXlsDataSource(InputStream is) throws JRException, IOException { try { this.workbook = Workbook.getWorkbook(is); this.closeWorkbook = true; } catch (BiffException e) { throw new JRException(e); } } /** * Creates a data source instance from an XLS file. * @param file a file containing XLS data */ public JRXlsDataSource(File file) throws JRException, FileNotFoundException, IOException { this(new FileInputStream(file)); } /** * */ public boolean next() throws JRException { recordIndex++; if (workbook != null) { if (recordIndex == 0 && useFirstRowAsHeader) { readHeader(); recordIndex++; } if (recordIndex < workbook.getSheet(0).getRows()) { return true; } else { if (closeWorkbook) { workbook.close(); } } } return false; } /** * */ public void moveFirst() { this.recordIndex = -1; } /** * */ public Object getFieldValue(JRField jrField) throws JRException { String fieldName = jrField.getName(); Integer columnIndex = (Integer) columnNames.get(fieldName); if (columnIndex == null && fieldName.startsWith("COLUMN_")) { columnIndex = Integer.valueOf(fieldName.substring(7)); } if (columnIndex == null) { throw new JRException("Unknown column name : " + fieldName); } Sheet sheet = workbook.getSheet(0); Cell cell = sheet.getCell(columnIndex.intValue(), recordIndex); String fieldValue = cell.getContents(); Class valueClass = jrField.getValueClass(); if (valueClass.equals(String.class)) { return fieldValue; } fieldValue = fieldValue.trim(); if (fieldValue.length() == 0) { return null; } try { if (valueClass.equals(Boolean.class)) { return fieldValue.equalsIgnoreCase("true") ? Boolean.TRUE : Boolean.FALSE; } else if (valueClass.equals(Byte.class)) { return new Byte((numberFormat.parse(fieldValue)).byteValue()); } else if (valueClass.equals(Integer.class)) { return Integer.valueOf((numberFormat.parse(fieldValue)).intValue()); } else if (valueClass.equals(Long.class)) { return new Long((numberFormat.parse(fieldValue)).longValue()); } else if (valueClass.equals(Short.class)) { return new Short((numberFormat.parse(fieldValue)).shortValue()); } else if (valueClass.equals(Double.class)) { return new Double((numberFormat.parse(fieldValue)).doubleValue()); } else if (valueClass.equals(Float.class)) { return new Float((numberFormat.parse(fieldValue)).floatValue()); } else if (valueClass.equals(BigDecimal.class)) { return new BigDecimal((numberFormat.parse(fieldValue)).toString()); } else if (valueClass.equals(BigInteger.class)) { return new BigInteger(String.valueOf(numberFormat.parse(fieldValue).longValue())); } else if(valueClass.equals(java.lang.Number.class)) { return numberFormat.parse(fieldValue); } else if (valueClass.equals(java.util.Date.class)) { return dateFormat.parse(fieldValue); } else if (valueClass.equals(java.sql.Timestamp.class)) { return new java.sql.Timestamp(dateFormat.parse(fieldValue).getTime()); } else if (valueClass.equals(java.sql.Time.class)) { return new java.sql.Time(dateFormat.parse(fieldValue).getTime()); } else { throw new JRException("Field '" + jrField.getName() + "' is of class '" + valueClass.getName() + "' and can not be converted"); } } catch (Exception e) { throw new JRException("Unable to get value for field '" + jrField.getName() + "' of class '" + valueClass.getName() + "'", e); } //throw new JRException("Unknown column name : " + fieldName); } /** * */ private void readHeader() { Sheet sheet = workbook.getSheet(0); if (columnNames.size() == 0) { for(int columnIndex = 0; columnIndex < sheet.getColumns(); columnIndex++) { Cell cell = sheet.getCell(columnIndex, recordIndex); String columnName = cell.getContents(); if (columnName != null && columnName.trim().length() > 0) { columnNames.put(columnName, Integer.valueOf(columnIndex)); } } } else { Map newColumnNames = new HashMap(); for(Iterator it = columnNames.values().iterator(); it.hasNext();) { Integer columnIndex = (Integer)it.next(); Cell cell = sheet.getCell(columnIndex.intValue(), recordIndex); String columnName = cell.getContents(); newColumnNames.put(columnName, columnIndex); } columnNames = newColumnNames; } } /** * Gets the date format that will be used to parse date fields. */ public DateFormat getDateFormat() { return dateFormat; } /** * Sets the desired date format to be used for parsing date fields. */ public void setDateFormat(DateFormat dateFormat) { checkReadStarted(); this.dateFormat = dateFormat; } /** * Gets the number format that will be used to parse numeric fields. */ public NumberFormat getNumberFormat() { return numberFormat; } /** * Sets the desired number format to be used for parsing numeric fields. */ public void setNumberFormat(NumberFormat numberFormat) { checkReadStarted(); this.numberFormat = numberFormat; } /** * Specifies an array of strings representing column names matching field names in the report template. */ public void setColumnNames(String[] columnNames) { checkReadStarted(); for (int i = 0; i < columnNames.length; i++) { this.columnNames.put(columnNames[i], Integer.valueOf(i)); } } /** * Specifies an array of strings representing column names matching field names in the report template * and an array of integers representing the column indexes in the sheet. * Both array parameters must be not-null and have the same number of values. */ public void setColumnNames(String[] columnNames, int[] columnIndexes) { checkReadStarted(); if (columnNames.length != columnIndexes.length) { throw new JRRuntimeException("The number of column names must be equal to the number of column indexes."); } for (int i = 0; i < columnNames.length; i++) { this.columnNames.put(columnNames[i], Integer.valueOf(columnIndexes[i])); } } /** * Specifies an array of integers representing the column indexes in the sheet. */ public void setColumnIndexes(Integer[] columnIndexes) { checkReadStarted(); for (int i = 0; i < columnIndexes.length; i++) { this.columnNames.put("COLUMN_" + i, columnIndexes[i]); } } /** * Specifies whether the first row of the XLS file should be considered a table * header, containing column names matching field names in the report template. */ public void setUseFirstRowAsHeader(boolean useFirstRowAsHeader) { checkReadStarted(); this.useFirstRowAsHeader = useFirstRowAsHeader; } /** * Closes the reader. Users of this data source should close it after usage. */ public void close() { try { inputStream.close(); } catch(IOException e) { //nothing to do } } private void checkReadStarted() { if (recordIndex > 0) { throw new JRRuntimeException("Cannot modify data source properties after data reading has started."); } } }