XmlProducer.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.xml;

  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.util.LinkedList;
  25. import java.util.List;

  26. import javax.xml.parsers.ParserConfigurationException;
  27. import javax.xml.parsers.SAXParserFactory;

  28. import org.dbunit.dataset.Column;
  29. import org.dbunit.dataset.DataSetException;
  30. import org.dbunit.dataset.DefaultTableMetaData;
  31. import org.dbunit.dataset.ITable;
  32. import org.dbunit.dataset.ITableMetaData;
  33. import org.dbunit.dataset.datatype.DataType;
  34. import org.dbunit.dataset.stream.DefaultConsumer;
  35. import org.dbunit.dataset.stream.IDataSetConsumer;
  36. import org.dbunit.dataset.stream.IDataSetProducer;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;
  39. import org.xml.sax.Attributes;
  40. import org.xml.sax.ContentHandler;
  41. import org.xml.sax.ErrorHandler;
  42. import org.xml.sax.InputSource;
  43. import org.xml.sax.SAXException;
  44. import org.xml.sax.SAXParseException;
  45. import org.xml.sax.XMLReader;
  46. import org.xml.sax.helpers.DefaultHandler;

  47. /**
  48.  * Parses an XML and produces a dataset from it.
  49.  *
  50.  * @author Manuel Laflamme
  51.  * @author Last changed by: $Author$
  52.  * @version $Revision$ $Date$
  53.  * @since Apr 30, 2003
  54.  */
  55. public class XmlProducer extends DefaultHandler
  56.         implements IDataSetProducer, ContentHandler, ErrorHandler
  57. {

  58.     /**
  59.      * Logger for this class
  60.      */
  61.     private static final Logger logger = LoggerFactory.getLogger(XmlProducer.class);

  62.     private static final IDataSetConsumer EMPTY_CONSUMER = new DefaultConsumer();

  63.     private static final String DATASET = "dataset";
  64.     private static final String TABLE = "table";
  65.     private static final String NAME = "name";
  66.     private static final String COLUMN = "column";
  67.     private static final String ROW = "row";
  68.     private static final String VALUE = "value";
  69.     private static final String NULL = "null";
  70.     private static final String NONE = "none";

  71.     private final InputSource _inputSource;
  72.     private boolean _validating = false;

  73.     private IDataSetConsumer _consumer = EMPTY_CONSUMER;


  74.     private String _activeTableName;
  75.     private ITableMetaData _activeMetaData;

  76.     private List _activeColumnNames;
  77.     private StringBuilder _activeCharacters;
  78.     private List _activeRowValues;

  79.     public XmlProducer(InputSource inputSource)
  80.     {
  81.         _inputSource = inputSource;
  82.     }

  83.     private ITableMetaData createMetaData(String tableName, List columnNames)
  84.     {
  85.         logger.debug("createMetaData(tableName={}, _columnNames={}) - start", tableName, columnNames);

  86.         Column[] columns = new Column[columnNames.size()];
  87.         for (int i = 0; i < columns.length; i++)
  88.         {
  89.             String columnName = (String)columnNames.get(i);
  90.             columns[i] = new Column(columnName, DataType.UNKNOWN);
  91.         }
  92.         DefaultTableMetaData metaData = new DefaultTableMetaData(tableName, columns);
  93.         return metaData;
  94.     }

  95.     public void setValidating(boolean validating)
  96.     {
  97.         _validating = validating;
  98.     }

  99.     ////////////////////////////////////////////////////////////////////////////
  100.     // IDataSetProducer interface

  101.     public void setConsumer(IDataSetConsumer consumer) throws DataSetException
  102.     {
  103.         logger.debug("setConsumer(consumer={}) - start", consumer);
  104.         _consumer = consumer;
  105.     }

  106.     public void produce() throws DataSetException
  107.     {
  108.         logger.debug("produce() - start");

  109.         try
  110.         {
  111.             SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
  112.             saxParserFactory.setValidating(_validating);
  113.             XMLReader xmlReader = saxParserFactory.newSAXParser().getXMLReader();

  114.             xmlReader.setContentHandler(this);
  115.             xmlReader.setEntityResolver(this);
  116.             xmlReader.setErrorHandler(this);
  117.             xmlReader.parse(_inputSource);
  118.         }
  119.         catch (ParserConfigurationException e)
  120.         {
  121.             throw new DataSetException(e);
  122.         }
  123.         catch (SAXException e)
  124.         {
  125.             DataSetException exceptionToRethrow = XmlProducer.buildException(e);
  126.             throw exceptionToRethrow;
  127.         }
  128.         catch (IOException e)
  129.         {
  130.             throw new DataSetException(e);
  131.         }
  132.     }

  133.     /**
  134.      * Wraps a {@link SAXException} into a {@link DataSetException}
  135.      * @param cause The cause to be wrapped into a {@link DataSetException}
  136.      * @return A {@link DataSetException} that wraps the given {@link SAXException}
  137.      */
  138.     protected final static DataSetException buildException(SAXException cause)
  139.     {
  140.         int lineNumber = -1;
  141.         if (cause instanceof SAXParseException)
  142.         {
  143.             lineNumber = ((SAXParseException)cause).getLineNumber();
  144.         }
  145.         Exception exception = cause.getException() == null ? cause : cause.getException();
  146.         String message;
  147.        
  148.         if (lineNumber >= 0)
  149.         {
  150.             message = "Line " + lineNumber + ": " + exception.getMessage();
  151.         }
  152.         else {
  153.             message = exception.getMessage();
  154.         }

  155.         if(exception instanceof DataSetException) {
  156.             return (DataSetException) exception;
  157.         }
  158.         else {
  159.             return new DataSetException(message, exception);
  160.         }
  161.     }

  162.     ////////////////////////////////////////////////////////////////////////////
  163.     // EntityResolver interface

  164.     public InputSource resolveEntity(String publicId, String systemId)
  165.             throws SAXException
  166.     {
  167.         logger.debug("resolveEntity(publicId={}, systemId={}) - start", publicId, systemId);

  168.         InputStream in = getClass().getClassLoader().getResourceAsStream(
  169.                 "org/dbunit/dataset/xml/dataset.dtd");
  170.         return (new InputSource(in));
  171.     }

  172.     ////////////////////////////////////////////////////////////////////////
  173.     // ContentHandler interface

  174.     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
  175.     {
  176.         logger.debug("startElement(uri={}, localName={}, qName={}, attributes={}) - start",
  177.             uri, localName, qName, attributes);

  178.         try
  179.         {
  180.             // dataset
  181.             if (qName.equals(DATASET))
  182.             {
  183.                 _consumer.startDataSet();
  184.                 return;
  185.             }

  186.             // table
  187.             if (qName.equals(TABLE))
  188.             {
  189.                 _activeTableName = attributes.getValue(NAME);
  190.                 _activeColumnNames = new LinkedList();
  191.                 return;
  192.             }

  193.             // column
  194.             if (qName.equals(COLUMN))
  195.             {
  196.                 _activeCharacters = new StringBuilder();
  197.                 return;
  198.             }

  199.             // row
  200.             if (qName.equals(ROW))
  201.             {
  202.                 // End of metadata at first row
  203.                 if (_activeColumnNames != null)
  204.                 {
  205.                     _activeMetaData = createMetaData(_activeTableName,_activeColumnNames);
  206.                     _consumer.startTable(_activeMetaData);
  207.                     _activeColumnNames = null;

  208.                 }

  209.                 _activeRowValues = new LinkedList();
  210.                 return;
  211.             }

  212.             // value
  213.             if (qName.equals(VALUE))
  214.             {
  215.                 _activeCharacters = new StringBuilder();
  216.                 return;
  217.             }

  218.             // null
  219.             if (qName.equals(NULL))
  220.             {
  221.                 _activeRowValues.add(null);
  222.                 return;
  223.             }

  224.             // none
  225.             if (qName.equals(NONE))
  226.             {
  227.                 _activeRowValues.add(ITable.NO_VALUE);
  228.                 return;
  229.             }
  230.         }
  231.         catch (DataSetException e)
  232.         {
  233.             throw new SAXException(e);
  234.         }
  235.     }

  236.     public void endElement(String uri, String localName, String qName) throws SAXException
  237.     {
  238.         logger.debug("endElement(uri={}, localName={}, qName={}) - start", uri, localName, qName);

  239.         try
  240.         {
  241.             // dataset
  242.             if (qName.equals(DATASET))
  243.             {
  244.                 _consumer.endDataSet();
  245.                 return;
  246.             }

  247.             // table
  248.             if (qName.equals(TABLE))
  249.             {
  250.                 // End of metadata
  251.                 if (_activeColumnNames != null)
  252.                 {
  253.                     _activeMetaData = createMetaData(_activeTableName, _activeColumnNames);
  254.                     _consumer.startTable(_activeMetaData);
  255.                     _activeColumnNames = null;
  256.                 }

  257.                 _consumer.endTable();
  258.                 _activeTableName = null;
  259.                 _activeMetaData = null;
  260.                 return;
  261.             }

  262.             // column
  263.             if (qName.equals(COLUMN))
  264.             {
  265.                 _activeColumnNames.add(_activeCharacters.toString());
  266.                 _activeCharacters = null;
  267.                 return;
  268.             }

  269.             // row
  270.             if (qName.equals(ROW))
  271.             {
  272.                 final int length = Math.max(_activeRowValues.size(), _activeMetaData.getColumns().length);
  273.                 Object[] values = new Object[length];
  274.                 for (int i = 0; i < values.length; i++)
  275.                 {
  276.                     values[i] = (i >= _activeRowValues.size()) ? ITable.NO_VALUE : _activeRowValues.get(i);
  277.                 }
  278.                 _consumer.row(values);
  279.                 _activeRowValues = null;
  280.                 return;
  281.             }

  282.             // value
  283.             if (qName.equals(VALUE))
  284.             {
  285.                 _activeRowValues.add(_activeCharacters.toString());
  286.                 _activeCharacters = null;
  287.                 return;
  288.             }

  289.             // null
  290.             if (qName.equals(NULL))
  291.             {
  292.                 // Nothing to do, already processed in startElement()
  293.                 return;
  294.             }

  295.             // none
  296.             if (qName.equals(NONE))
  297.             {
  298.                 // Nothing to do, already processed in startElement()
  299.                 return;
  300.             }
  301.         }
  302.         catch (DataSetException e)
  303.         {
  304.             throw new SAXException(e);
  305.         }
  306.     }

  307.     public void characters(char ch[], int start, int length)
  308.             throws SAXException
  309.     {
  310.         if (_activeCharacters != null)
  311.         {
  312.             _activeCharacters.append(ch, start, length);
  313.         }
  314.     }

  315.     ////////////////////////////////////////////////////////////////////////////
  316.     // ErrorHandler interface

  317. //    public void warning(SAXParseException e)
  318. //            throws SAXException
  319. //    {
  320. //        throw e;
  321. //    }

  322.     public void error(SAXParseException e)
  323.             throws SAXException
  324.     {
  325.         throw e;
  326.     }

  327. //    public void fatalError(SAXParseException e)
  328. //            throws SAXException
  329. //    {
  330. //        throw e;
  331. //    }


  332. }