1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit.dataset.xml;
22
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.util.LinkedList;
26 import java.util.List;
27
28 import javax.xml.parsers.ParserConfigurationException;
29 import javax.xml.parsers.SAXParserFactory;
30
31 import org.dbunit.dataset.Column;
32 import org.dbunit.dataset.DataSetException;
33 import org.dbunit.dataset.DefaultTableMetaData;
34 import org.dbunit.dataset.ITable;
35 import org.dbunit.dataset.ITableMetaData;
36 import org.dbunit.dataset.datatype.DataType;
37 import org.dbunit.dataset.stream.DefaultConsumer;
38 import org.dbunit.dataset.stream.IDataSetConsumer;
39 import org.dbunit.dataset.stream.IDataSetProducer;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.xml.sax.Attributes;
43 import org.xml.sax.ContentHandler;
44 import org.xml.sax.ErrorHandler;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47 import org.xml.sax.SAXParseException;
48 import org.xml.sax.XMLReader;
49 import org.xml.sax.helpers.DefaultHandler;
50
51
52
53
54
55
56
57
58
59 public class XmlProducer extends DefaultHandler
60 implements IDataSetProducer, ContentHandler, ErrorHandler
61 {
62
63
64
65
66 private static final Logger logger = LoggerFactory.getLogger(XmlProducer.class);
67
68 private static final IDataSetConsumer EMPTY_CONSUMER = new DefaultConsumer();
69
70 private static final String DATASET = "dataset";
71 private static final String TABLE = "table";
72 private static final String NAME = "name";
73 private static final String COLUMN = "column";
74 private static final String ROW = "row";
75 private static final String VALUE = "value";
76 private static final String NULL = "null";
77 private static final String NONE = "none";
78
79 private final InputSource _inputSource;
80 private boolean _validating = false;
81
82 private IDataSetConsumer _consumer = EMPTY_CONSUMER;
83
84
85 private String _activeTableName;
86 private ITableMetaData _activeMetaData;
87
88 private List _activeColumnNames;
89 private StringBuffer _activeCharacters;
90 private List _activeRowValues;
91
92 public XmlProducer(InputSource inputSource)
93 {
94 _inputSource = inputSource;
95 }
96
97 private ITableMetaData createMetaData(String tableName, List columnNames)
98 {
99 logger.debug("createMetaData(tableName={}, _columnNames={}) - start", tableName, columnNames);
100
101 Column[] columns = new Column[columnNames.size()];
102 for (int i = 0; i < columns.length; i++)
103 {
104 String columnName = (String)columnNames.get(i);
105 columns[i] = new Column(columnName, DataType.UNKNOWN);
106 }
107 DefaultTableMetaData metaData = new DefaultTableMetaData(tableName, columns);
108 return metaData;
109 }
110
111 public void setValidating(boolean validating)
112 {
113 _validating = validating;
114 }
115
116
117
118
119 public void setConsumer(IDataSetConsumer consumer) throws DataSetException
120 {
121 logger.debug("setConsumer(consumer={}) - start", consumer);
122 _consumer = consumer;
123 }
124
125 public void produce() throws DataSetException
126 {
127 logger.debug("produce() - start");
128
129 try
130 {
131 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
132 saxParserFactory.setValidating(_validating);
133 XMLReader xmlReader = saxParserFactory.newSAXParser().getXMLReader();
134
135 xmlReader.setContentHandler(this);
136 xmlReader.setEntityResolver(this);
137 xmlReader.setErrorHandler(this);
138 xmlReader.parse(_inputSource);
139 }
140 catch (ParserConfigurationException e)
141 {
142 throw new DataSetException(e);
143 }
144 catch (SAXException e)
145 {
146 DataSetException exceptionToRethrow = XmlProducer.buildException(e);
147 throw exceptionToRethrow;
148 }
149 catch (IOException e)
150 {
151 throw new DataSetException(e);
152 }
153 }
154
155
156
157
158
159
160 protected final static DataSetException buildException(SAXException cause)
161 {
162 int lineNumber = -1;
163 if (cause instanceof SAXParseException)
164 {
165 lineNumber = ((SAXParseException)cause).getLineNumber();
166 }
167 Exception exception = cause.getException() == null ? cause : cause.getException();
168 String message;
169
170 if (lineNumber >= 0)
171 {
172 message = "Line " + lineNumber + ": " + exception.getMessage();
173 }
174 else {
175 message = exception.getMessage();
176 }
177
178 if(exception instanceof DataSetException) {
179 return (DataSetException) exception;
180 }
181 else {
182 return new DataSetException(message, exception);
183 }
184 }
185
186
187
188
189 public InputSource resolveEntity(String publicId, String systemId)
190 throws SAXException
191 {
192 logger.debug("resolveEntity(publicId={}, systemId={}) - start", publicId, systemId);
193
194 InputStream in = getClass().getClassLoader().getResourceAsStream(
195 "org/dbunit/dataset/xml/dataset.dtd");
196 return (new InputSource(in));
197 }
198
199
200
201
202 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
203 {
204 if (logger.isDebugEnabled())
205 {
206 logger.debug("startElement(uri={}, localName={}, qName={}, attributes={}) - start",
207 new Object[]{ uri, localName, qName, attributes });
208 }
209
210 try
211 {
212
213 if (qName.equals(DATASET))
214 {
215 _consumer.startDataSet();
216 return;
217 }
218
219
220 if (qName.equals(TABLE))
221 {
222 _activeTableName = attributes.getValue(NAME);
223 _activeColumnNames = new LinkedList();
224 return;
225 }
226
227
228 if (qName.equals(COLUMN))
229 {
230 _activeCharacters = new StringBuffer();
231 return;
232 }
233
234
235 if (qName.equals(ROW))
236 {
237
238 if (_activeColumnNames != null)
239 {
240 _activeMetaData = createMetaData(_activeTableName,_activeColumnNames);
241 _consumer.startTable(_activeMetaData);
242 _activeColumnNames = null;
243
244 }
245
246 _activeRowValues = new LinkedList();
247 return;
248 }
249
250
251 if (qName.equals(VALUE))
252 {
253 _activeCharacters = new StringBuffer();
254 return;
255 }
256
257
258 if (qName.equals(NULL))
259 {
260 _activeRowValues.add(null);
261 return;
262 }
263
264
265 if (qName.equals(NONE))
266 {
267 _activeRowValues.add(ITable.NO_VALUE);
268 return;
269 }
270 }
271 catch (DataSetException e)
272 {
273 throw new SAXException(e);
274 }
275 }
276
277 public void endElement(String uri, String localName, String qName) throws SAXException
278 {
279 if (logger.isDebugEnabled())
280 {
281 logger.debug("endElement(uri={}, localName={}, qName={}) - start",
282 new Object[]{ uri, localName, qName });
283 }
284
285 try
286 {
287
288 if (qName.equals(DATASET))
289 {
290 _consumer.endDataSet();
291 return;
292 }
293
294
295 if (qName.equals(TABLE))
296 {
297
298 if (_activeColumnNames != null)
299 {
300 _activeMetaData = createMetaData(_activeTableName, _activeColumnNames);
301 _consumer.startTable(_activeMetaData);
302 _activeColumnNames = null;
303 }
304
305 _consumer.endTable();
306 _activeTableName = null;
307 _activeMetaData = null;
308 return;
309 }
310
311
312 if (qName.equals(COLUMN))
313 {
314 _activeColumnNames.add(_activeCharacters.toString());
315 _activeCharacters = null;
316 return;
317 }
318
319
320 if (qName.equals(ROW))
321 {
322 final int length = Math.max(_activeRowValues.size(), _activeMetaData.getColumns().length);
323 Object[] values = new Object[length];
324 for (int i = 0; i < values.length; i++)
325 {
326 values[i] = (i >= _activeRowValues.size()) ? ITable.NO_VALUE : _activeRowValues.get(i);
327 }
328 _consumer.row(values);
329 _activeRowValues = null;
330 return;
331 }
332
333
334 if (qName.equals(VALUE))
335 {
336 _activeRowValues.add(_activeCharacters.toString());
337 _activeCharacters = null;
338 return;
339 }
340
341
342 if (qName.equals(NULL))
343 {
344
345 return;
346 }
347
348
349 if (qName.equals(NONE))
350 {
351
352 return;
353 }
354 }
355 catch (DataSetException e)
356 {
357 throw new SAXException(e);
358 }
359 }
360
361 public void characters(char ch[], int start, int length)
362 throws SAXException
363 {
364 if (_activeCharacters != null)
365 {
366 _activeCharacters.append(ch, start, length);
367 }
368 }
369
370
371
372
373
374
375
376
377
378
379 public void error(SAXParseException e)
380 throws SAXException
381 {
382 throw e;
383 }
384
385
386
387
388
389
390
391
392 }