001: /*
002: *
003: * The DbUnit Database Testing Framework
004: * Copyright (C)2002-2004, DbUnit.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: */
021: package org.dbunit.dataset.xml;
022:
023: import org.slf4j.Logger;
024: import org.slf4j.LoggerFactory;
025:
026: import org.dbunit.dataset.*;
027: import org.dbunit.dataset.datatype.DataType;
028: import org.dbunit.dataset.stream.DefaultConsumer;
029: import org.dbunit.dataset.stream.IDataSetConsumer;
030: import org.dbunit.dataset.stream.IDataSetProducer;
031: import org.xml.sax.*;
032: import org.xml.sax.helpers.DefaultHandler;
033:
034: import javax.xml.parsers.ParserConfigurationException;
035: import javax.xml.parsers.SAXParserFactory;
036: import java.io.IOException;
037: import java.io.StringReader;
038:
039: /**
040: * @author Manuel Laflamme
041: * @since Apr 18, 2003
042: * @version $Revision: 558 $
043: */
044: public class FlatXmlProducer extends DefaultHandler implements
045: IDataSetProducer, ContentHandler {
046:
047: /**
048: * Logger for this class
049: */
050: private static final Logger logger = LoggerFactory
051: .getLogger(FlatXmlProducer.class);
052:
053: private static final IDataSetConsumer EMPTY_CONSUMER = new DefaultConsumer();
054: private static final String DATASET = "dataset";
055:
056: private final InputSource _inputSource;
057: private final EntityResolver _resolver;
058: private final boolean _dtdMetadata;
059: private boolean _validating = false;
060: private IDataSet _metaDataSet;
061:
062: private IDataSetConsumer _consumer = EMPTY_CONSUMER;
063: private ITableMetaData _activeMetaData;
064:
065: public FlatXmlProducer(InputSource xmlSource) {
066: _inputSource = xmlSource;
067: _resolver = this ;
068: _dtdMetadata = true;
069: _validating = false;
070: }
071:
072: public FlatXmlProducer(InputSource xmlSource, boolean dtdMetadata) {
073: _inputSource = xmlSource;
074: _resolver = this ;
075: _dtdMetadata = dtdMetadata;
076: _validating = false;
077: }
078:
079: public FlatXmlProducer(InputSource xmlSource, IDataSet metaDataSet) {
080: _inputSource = xmlSource;
081: _metaDataSet = metaDataSet;
082: _resolver = this ;
083: _dtdMetadata = false;
084: _validating = false;
085: }
086:
087: public FlatXmlProducer(InputSource xmlSource,
088: EntityResolver resolver) {
089: _inputSource = xmlSource;
090: _resolver = resolver;
091: _dtdMetadata = true;
092: _validating = false;
093: }
094:
095: // public FlatXmlProducer(InputSource inputSource, XMLReader xmlReader)
096: // {
097: // _inputSource = inputSource;
098: // _xmlReader = xmlReader;
099: // }
100:
101: private ITableMetaData createTableMetaData(String tableName,
102: Attributes attributes) throws DataSetException {
103: logger.debug("createTableMetaData(tableName=" + tableName
104: + ", attributes=" + attributes + ") - start");
105:
106: if (_metaDataSet != null) {
107: return _metaDataSet.getTableMetaData(tableName);
108: }
109:
110: // Create metadata from attributes
111: Column[] columns = new Column[attributes.getLength()];
112: for (int i = 0; i < attributes.getLength(); i++) {
113: columns[i] = new Column(attributes.getQName(i),
114: DataType.UNKNOWN);
115: }
116:
117: return new DefaultTableMetaData(tableName, columns);
118: }
119:
120: public void setValidating(boolean validating) {
121: logger.debug("setValidating(validating=" + validating
122: + ") - start");
123:
124: _validating = validating;
125: }
126:
127: ////////////////////////////////////////////////////////////////////////////
128: // IDataSetProducer interface
129:
130: public void setConsumer(IDataSetConsumer consumer)
131: throws DataSetException {
132: logger.debug("setConsumer(consumer) - start");
133:
134: _consumer = consumer;
135: }
136:
137: public void produce() throws DataSetException {
138: logger.debug("produce() - start");
139:
140: try {
141: SAXParserFactory saxParserFactory = SAXParserFactory
142: .newInstance();
143: saxParserFactory.setValidating(_validating);
144: XMLReader xmlReader = saxParserFactory.newSAXParser()
145: .getXMLReader();
146:
147: if (_dtdMetadata) {
148: FlatDtdHandler dtdHandler = new FlatDtdHandler();
149: FlatDtdHandler.setLexicalHandler(xmlReader, dtdHandler);
150: FlatDtdHandler.setDeclHandler(xmlReader, dtdHandler);
151: }
152:
153: xmlReader.setContentHandler(this );
154: xmlReader.setErrorHandler(this );
155: xmlReader.setEntityResolver(_resolver);
156: xmlReader.parse(_inputSource);
157: } catch (ParserConfigurationException e) {
158: logger.error("produce()", e);
159:
160: throw new DataSetException(e);
161: } catch (SAXException e) {
162: logger.error("produce()", e);
163:
164: int lineNumber = -1;
165: if (e instanceof SAXParseException) {
166: lineNumber = ((SAXParseException) e).getLineNumber();
167: }
168: Exception exception = e.getException() == null ? e : e
169: .getException();
170:
171: if (lineNumber >= 0) {
172: String message = "Line " + lineNumber + ": "
173: + exception.getMessage();
174: throw new DataSetException(message, e);
175: }
176: throw new DataSetException(exception);
177: } catch (IOException e) {
178: logger.error("produce()", e);
179:
180: throw new DataSetException(e);
181: }
182: }
183:
184: ////////////////////////////////////////////////////////////////////////////
185: // EntityResolver interface
186:
187: public InputSource resolveEntity(String publicId, String systemId)
188: throws SAXException {
189: logger.debug("resolveEntity(publicId=" + publicId
190: + ", systemId=" + systemId + ") - start");
191:
192: if (!_dtdMetadata) {
193: return new InputSource(new StringReader(""));
194: }
195: return null;
196: }
197:
198: ////////////////////////////////////////////////////////////////////////////
199: // ErrorHandler interface
200:
201: public void error(SAXParseException e) throws SAXException {
202: logger.debug("error(e=" + e + ") - start");
203:
204: throw e;
205:
206: }
207:
208: ////////////////////////////////////////////////////////////////////////
209: // ContentHandler interface
210:
211: public void startElement(String uri, String localName,
212: String qName, Attributes attributes) throws SAXException {
213: logger.debug("startElement(uri=" + uri + ", localName="
214: + localName + ", qName=" + qName + ", attributes="
215: + attributes + ") - start");
216:
217: try {
218: // Start of dataset
219: if (_activeMetaData == null && qName.equals(DATASET)) {
220: _consumer.startDataSet();
221: return;
222: }
223:
224: // New table
225: if (_activeMetaData == null
226: || !_activeMetaData.getTableName().equals(qName)) {
227: // If not first table, notify end of previous table to consumer
228: if (_activeMetaData != null) {
229: _consumer.endTable();
230: }
231:
232: // Notify start of new table to consumer
233: _activeMetaData = createTableMetaData(qName, attributes);
234: _consumer.startTable(_activeMetaData);
235: }
236:
237: // Row notification
238: if (attributes.getLength() > 0) {
239: Column[] columns = _activeMetaData.getColumns();
240: Object[] rowValues = new Object[columns.length];
241: for (int i = 0; i < columns.length; i++) {
242: Column column = columns[i];
243: rowValues[i] = attributes.getValue(column
244: .getColumnName());
245: }
246: _consumer.row(rowValues);
247: }
248: } catch (DataSetException e) {
249: logger.error("startElement()", e);
250:
251: throw new SAXException(e);
252: }
253: }
254:
255: public void endElement(String uri, String localName, String qName)
256: throws SAXException {
257: logger.debug("endElement(uri=" + uri + ", localName="
258: + localName + ", qName=" + qName + ") - start");
259:
260: // End of dataset
261: if (qName.equals(DATASET)) {
262: try {
263: // Notify end of active table to consumer
264: if (_activeMetaData != null) {
265: _consumer.endTable();
266: }
267:
268: // Notify end of dataset to consumer
269: _consumer.endDataSet();
270: } catch (DataSetException e) {
271: logger.error("endElement()", e);
272:
273: throw new SAXException(e);
274: }
275: }
276: }
277:
278: private class FlatDtdHandler extends FlatDtdProducer {
279:
280: /**
281: * Logger for this class
282: */
283: private final Logger logger = LoggerFactory
284: .getLogger(FlatDtdHandler.class);
285:
286: public FlatDtdHandler() {
287: }
288:
289: ////////////////////////////////////////////////////////////////////////////
290: // LexicalHandler interface
291:
292: public void startDTD(String name, String publicId,
293: String systemId) throws SAXException {
294: logger
295: .debug("startDTD(name=" + name + ", publicId="
296: + publicId + ", systemId=" + systemId
297: + ") - start");
298:
299: try {
300: // Cache the DTD content to use it as metadata
301: FlatDtdDataSet metaDataSet = new FlatDtdDataSet();
302: this .setConsumer(metaDataSet);
303: _metaDataSet = metaDataSet;
304:
305: super .startDTD(name, publicId, systemId);
306: } catch (DataSetException e) {
307: logger.error("startDTD()", e);
308:
309: throw new SAXException(e);
310: }
311: }
312: }
313:
314: }
|