/** * Copyright (c) 2009--2014 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.common.util; import com.redhat.rhn.common.localization.LocalizationService; import com.redhat.rhn.frontend.dto.BaseDto; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.NestedNullException; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * CSVWriter - util class for writing objects into CSV * @version $Rev$ */ public class CSVWriter extends BufferedWriter implements ExportWriter { private List <String> columns; private Writer contents; private String headerText; private char separatorChar = ','; /** * Constructor * @param out Writer to send CSV to */ public CSVWriter(Writer out) { super(out); this.contents = out; this.headerText = null; } /** * Constructor * @param out Writer to send CSV to * @param separator Separator character to use */ public CSVWriter(Writer out, char separator) { this(out); this.separatorChar = separator; } /** * Set columns * @param columnsIn List of Strings containing the names of the columns */ public void setColumns(List<String> columnsIn) { columns = new LinkedList<String>(); for (String column : columnsIn) { columns.add(column.trim()); } } /** * Sets an optional header string. * @param headerIn This will become the * first line of the export CSV contents. */ public void setHeaderText(String headerIn) { headerText = headerIn; } /** * @return String Description of exported data with commas appended * to correspond to the number of columns being exported. Needed so * it doesn't break applications which will be parsing this data. * */ public String getHeaderText() { String hdrStr = headerText; if (hdrStr != null) { for (int i = 0; i < columns.size() - 1; i++) { hdrStr += separatorChar; } } return hdrStr; } /** * Write the header to the stream */ public void writeHeader() { write(columns); } /** * {@inheritDoc} */ public void write(List listIn) { try { this.writeList(listIn); } catch (IOException e) { throw new RuntimeException("IOException caught trying to write the list: " + e); } } /** * Write a List to the stream * @param values you want to write * @throws IOException if there is error */ private void writeList(List values) throws IOException { Iterator itr = values.iterator(); // Write out the column headers if (columns != null) { Iterator citer = columns.iterator(); while (citer.hasNext()) { String cname = (String) citer.next(); if (LocalizationService. getInstance().hasMessage("exportcolumn." + cname)) { write(LocalizationService. getInstance().getMessage("exportcolumn." + cname)); } else { write(LocalizationService. getInstance().getMessage(cname)); } if (citer.hasNext()) { writeSeparator(); } } newLine(); } // Iterate over the values while (itr.hasNext()) { Object value = itr.next(); // If its a List of Strings if (value instanceof String) { write((String) value); if (itr.hasNext()) { writeSeparator(); } } // If its a list of Maps or Dtos else if (value instanceof Map || value instanceof BaseDto) { if (columns == null || !columns.iterator().hasNext()) { throw new IllegalArgumentException("Tried to csv export without" + " setting up the list of columns first"); } Iterator citer = columns.iterator(); while (citer.hasNext()) { String columnKey = (String) citer.next(); Object colVal = getObjectValue(value, columnKey); if (colVal != null) { write(colVal.toString()); } if (citer.hasNext()) { writeSeparator(); } } if (itr.hasNext()) { newLine(); } } else { throw new IllegalArgumentException("Must pass in a List of Strings, " + "Maps or AbstractDto classes"); } } // Its always good to end a file with // a newline. newLine(); } /** * Util function to get the value for the current row/column in the List. */ private Object getObjectValue(Object row, String columnKey) { if (row instanceof Map) { Map rowmap = (Map) row; return rowmap.get(columnKey); } else if (row instanceof BaseDto) { String ovalue = null; try { ovalue = BeanUtils.getProperty(row, columnKey); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Can't access method in DTO: get" + columnKey + "(), IllegalAccessException:" + e.toString()); } catch (InvocationTargetException e) { throw new IllegalArgumentException("Can't access method in DTO: get" + columnKey + "(), InvocationTargetException:" + e.toString()); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Can't call method in DTO class: " + row.getClass().getName() + "." + "get" + columnKey + "(), NoSuchMethodException: " + e.toString()); } catch (NestedNullException e) { return null; } return ovalue; } return null; } /** * Write a string to the Writer * {@inheritDoc} */ public void write(String s) throws IOException { // If the string does not contain a comma, just write it out if (s.indexOf(separatorChar) == -1 && s.indexOf('"') == -1) { super.write(s); return; } // If the string does have a comma, then write it out // surrounded by quotation marks. Any quotation mark in the // string must be doubled. super.write("\""); int from = 0; for (;;) { int to = s.indexOf('"', from); if (to == -1) { super.write(s, from, s.length() - from); break; } super.write(s, from, to - from); super.write("\"\""); from = to + 1; } super.write("\""); } /** * Write the separator to the Writer * @throws IOException if there is a Writer error */ public void writeSeparator() throws IOException { super.write(separatorChar); } /** * {@inheritDoc} */ public String getContents() { try { this.flush(); } catch (IOException e) { throw new IllegalStateException("Caught IOException while " + "trying to flush contents for output: " + e); } if (headerText != null) { return getHeaderText() + System.getProperty("line.separator") + this.contents.toString(); } return this.contents.toString(); } /** * {@inheritDoc} */ public String getMimeType() { return "text/csv"; } /** * {@inheritDoc} */ public String getFileExtension() { return "csv"; } }