CsvParserImpl.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2004, DbUnit.org
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  */

  21. package org.dbunit.dataset.csv;

  22. import java.io.BufferedReader;
  23. import java.io.File;
  24. import java.io.FileInputStream;
  25. import java.io.IOException;
  26. import java.io.InputStreamReader;
  27. import java.io.LineNumberReader;
  28. import java.io.Reader;
  29. import java.net.URL;
  30. import java.text.CharacterIterator;
  31. import java.text.StringCharacterIterator;
  32. import java.util.ArrayList;
  33. import java.util.List;

  34. import org.dbunit.dataset.common.handlers.EscapeHandler;
  35. import org.dbunit.dataset.common.handlers.IllegalInputCharacterException;
  36. import org.dbunit.dataset.common.handlers.IsAlnumHandler;
  37. import org.dbunit.dataset.common.handlers.Pipeline;
  38. import org.dbunit.dataset.common.handlers.PipelineException;
  39. import org.dbunit.dataset.common.handlers.QuoteHandler;
  40. import org.dbunit.dataset.common.handlers.SeparatorHandler;
  41. import org.dbunit.dataset.common.handlers.TransparentHandler;
  42. import org.dbunit.dataset.common.handlers.WhitespacesHandler;
  43. import org.slf4j.Logger;
  44. import org.slf4j.LoggerFactory;

  45. /**
  46.  * @author fede
  47.  * @author Last changed by: $Author$
  48.  * @version $Revision$ $Date$
  49.  * @since 2.2 (Sep 12, 2004)
  50.  */
  51. public class CsvParserImpl implements CsvParser {

  52.     /**
  53.      * Logger for this class
  54.      */
  55.     private static final Logger logger = LoggerFactory.getLogger(CsvParserImpl.class);

  56.     private Pipeline pipeline;

  57.     public CsvParserImpl() {
  58.         resetThePipeline();
  59.     }

  60.     private void resetThePipeline() {
  61.         logger.debug("resetThePipeline() - start");

  62.         pipeline = new Pipeline();
  63.         getPipeline().putFront(SeparatorHandler.ENDPIECE());
  64.         getPipeline().putFront(EscapeHandler.ACCEPT());
  65.         getPipeline().putFront(IsAlnumHandler.QUOTE());
  66.         getPipeline().putFront(QuoteHandler.QUOTE());
  67.         getPipeline().putFront(EscapeHandler.ESCAPE());
  68.         getPipeline().putFront(WhitespacesHandler.IGNORE());
  69.         getPipeline().putFront(TransparentHandler.IGNORE());
  70.     }

  71.     public List parse(String csv) throws PipelineException, IllegalInputCharacterException {
  72.         logger.debug("parse(csv={}) - start", csv);

  73.         getPipeline().resetProducts();
  74.         CharacterIterator iterator = new StringCharacterIterator(csv);
  75.         for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
  76.             getPipeline().handle(c);
  77.         }
  78.         getPipeline().noMoreInput();
  79.         getPipeline().thePieceIsDone();
  80.         return getPipeline().getProducts();
  81.     }

  82.     public List parse(File file) throws IOException, CsvParserException {
  83.         logger.debug("parse(file={}) - start", file);

  84.         BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
  85.         try {
  86.             return parse(reader, file.getAbsolutePath().toString());
  87.         }
  88.         finally {
  89.             reader.close();
  90.         }
  91.     }
  92.    
  93.     public List parse(URL url) throws IOException, CsvParserException {
  94.         logger.debug("parse(url={}) - start", url);

  95.         BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
  96.         try {
  97.             return parse(reader, url.toString());
  98.         }
  99.         finally {
  100.             reader.close();
  101.         }
  102.     }
  103.    
  104.     public List parse(Reader reader, String source) throws IOException, CsvParserException {
  105.         logger.debug("parse(reader={}, source={}) - start", reader, source);

  106.         LineNumberReader lineNumberReader = new LineNumberReader(reader);
  107.         List rows = new ArrayList();
  108.         List columnsInFirstLine = parseFirstLine(lineNumberReader, source, rows);
  109.         parseTheData(columnsInFirstLine, lineNumberReader, rows);
  110.         return rows;
  111.     }

  112. //    private List parseFirstLine(LineNumberReader lineNumberReader, File file, List rows) throws IOException, CsvParserException {
  113. //        if(logger.isDebugEnabled())
  114. //            logger.debug("parseFirstLine(lineNumberReader={}, file={}, rows={}) - start",
  115. //                new Object[]{lineNumberReader, file, rows} );
  116. //
  117. //      return parseFirstLine(lineNumberReader, file.getAbsolutePath().toString(), rows);
  118. //    }

  119.     /**
  120.      * parse the first line of data from the given source
  121.      */
  122.     private List parseFirstLine(LineNumberReader lineNumberReader, String source, List rows) throws IOException, CsvParserException {
  123.         if(logger.isDebugEnabled())
  124.             logger.debug("parseFirstLine(lineNumberReader={}, source={}, rows={}) - start",
  125.                 new Object[]{lineNumberReader,source,rows});

  126.         String firstLine = lineNumberReader.readLine();
  127.         if (firstLine == null)
  128.             throw new CsvParserException("The first line of " + source + " is null");

  129.         final List columnsInFirstLine = parse(firstLine);
  130.         rows.add(columnsInFirstLine);
  131.         return columnsInFirstLine;
  132.     }

  133.     private void parseTheData(final List columnsInFirstLine, LineNumberReader lineNumberReader, List rows) throws IOException, CsvParserException {
  134.         logger.debug("parseTheData(columnsInFirstLine={}, lineNumberReader={}, rows={}) - start",
  135.                 new Object[] {columnsInFirstLine, lineNumberReader, rows} );

  136.         int nColumns = columnsInFirstLine.size();
  137.         List columns;
  138.         while ((columns = collectExpectedNumberOfColumns(nColumns, lineNumberReader)) != null) {
  139.             rows.add(columns);
  140.         }
  141.     }

  142.     private List collectExpectedNumberOfColumns(int expectedNumberOfColumns, LineNumberReader lineNumberReader) throws IOException, CsvParserException  {
  143.         if(logger.isDebugEnabled())
  144.             logger.debug("collectExpectedNumberOfColumns(expectedNumberOfColumns={}, lineNumberReader={}) - start",
  145.                 String.valueOf(expectedNumberOfColumns), lineNumberReader);

  146.         List columns = null;
  147.         int columnsCollectedSoFar = 0;
  148.         final StringBuilder buffer = new StringBuilder();
  149.         String anotherLine = lineNumberReader.readLine();
  150.         if(anotherLine == null)
  151.             return null;
  152.         boolean shouldProceed = false;
  153.         while (columnsCollectedSoFar < expectedNumberOfColumns) {
  154.             try {
  155.                 buffer.append(anotherLine);
  156.                 columns = parse(buffer.toString());
  157.                 columnsCollectedSoFar = columns.size();
  158.             } catch (IllegalStateException e) {
  159.                 resetThePipeline();
  160.                 anotherLine = lineNumberReader.readLine();
  161.                 if(anotherLine == null)
  162.                     break;
  163.                 buffer.append("\n");
  164.                 shouldProceed = true;
  165.             }
  166.             if (!shouldProceed)
  167.                 break;
  168.         }
  169.         if (columnsCollectedSoFar != expectedNumberOfColumns) {
  170.             String message = new StringBuilder("Expected ").append(expectedNumberOfColumns)
  171.                     .append(" columns on line ").append(lineNumberReader.getLineNumber())
  172.                     .append(", got ").append(columnsCollectedSoFar).append(". Offending line: ").append(buffer).toString();
  173.             throw new CsvParserException(message);
  174.         }
  175.         return columns;
  176.     }

  177.     Pipeline getPipeline() {
  178.         logger.debug("getPipeline() - start");

  179.         return pipeline;
  180.     }

  181.     void setPipeline(Pipeline pipeline) {
  182.         logger.debug("setPipeline(pipeline={}) - start", pipeline);

  183.         this.pipeline = pipeline;
  184.     }
  185. }