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 StringBuilder _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 logger.debug("startElement(uri={}, localName={}, qName={}, attributes={}) - start",
205 uri, localName, qName, attributes);
206
207 try
208 {
209
210 if (qName.equals(DATASET))
211 {
212 _consumer.startDataSet();
213 return;
214 }
215
216
217 if (qName.equals(TABLE))
218 {
219 _activeTableName = attributes.getValue(NAME);
220 _activeColumnNames = new LinkedList();
221 return;
222 }
223
224
225 if (qName.equals(COLUMN))
226 {
227 _activeCharacters = new StringBuilder();
228 return;
229 }
230
231
232 if (qName.equals(ROW))
233 {
234
235 if (_activeColumnNames != null)
236 {
237 _activeMetaData = createMetaData(_activeTableName,_activeColumnNames);
238 _consumer.startTable(_activeMetaData);
239 _activeColumnNames = null;
240
241 }
242
243 _activeRowValues = new LinkedList();
244 return;
245 }
246
247
248 if (qName.equals(VALUE))
249 {
250 _activeCharacters = new StringBuilder();
251 return;
252 }
253
254
255 if (qName.equals(NULL))
256 {
257 _activeRowValues.add(null);
258 return;
259 }
260
261
262 if (qName.equals(NONE))
263 {
264 _activeRowValues.add(ITable.NO_VALUE);
265 return;
266 }
267 }
268 catch (DataSetException e)
269 {
270 throw new SAXException(e);
271 }
272 }
273
274 public void endElement(String uri, String localName, String qName) throws SAXException
275 {
276 logger.debug("endElement(uri={}, localName={}, qName={}) - start", uri, localName, qName);
277
278 try
279 {
280
281 if (qName.equals(DATASET))
282 {
283 _consumer.endDataSet();
284 return;
285 }
286
287
288 if (qName.equals(TABLE))
289 {
290
291 if (_activeColumnNames != null)
292 {
293 _activeMetaData = createMetaData(_activeTableName, _activeColumnNames);
294 _consumer.startTable(_activeMetaData);
295 _activeColumnNames = null;
296 }
297
298 _consumer.endTable();
299 _activeTableName = null;
300 _activeMetaData = null;
301 return;
302 }
303
304
305 if (qName.equals(COLUMN))
306 {
307 _activeColumnNames.add(_activeCharacters.toString());
308 _activeCharacters = null;
309 return;
310 }
311
312
313 if (qName.equals(ROW))
314 {
315 final int length = Math.max(_activeRowValues.size(), _activeMetaData.getColumns().length);
316 Object[] values = new Object[length];
317 for (int i = 0; i < values.length; i++)
318 {
319 values[i] = (i >= _activeRowValues.size()) ? ITable.NO_VALUE : _activeRowValues.get(i);
320 }
321 _consumer.row(values);
322 _activeRowValues = null;
323 return;
324 }
325
326
327 if (qName.equals(VALUE))
328 {
329 _activeRowValues.add(_activeCharacters.toString());
330 _activeCharacters = null;
331 return;
332 }
333
334
335 if (qName.equals(NULL))
336 {
337
338 return;
339 }
340
341
342 if (qName.equals(NONE))
343 {
344
345 return;
346 }
347 }
348 catch (DataSetException e)
349 {
350 throw new SAXException(e);
351 }
352 }
353
354 public void characters(char ch[], int start, int length)
355 throws SAXException
356 {
357 if (_activeCharacters != null)
358 {
359 _activeCharacters.append(ch, start, length);
360 }
361 }
362
363
364
365
366
367
368
369
370
371
372 public void error(SAXParseException e)
373 throws SAXException
374 {
375 throw e;
376 }
377
378
379
380
381
382
383
384
385 }