1 /*
2 *
3 * The DbUnit Database Testing Framework
4 * Copyright (C)2002-2009, 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
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.Reader;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29
30 import org.dbunit.dataset.DataSetException;
31 import org.dbunit.dataset.IDataSet;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.xml.sax.InputSource;
35
36 /**
37 * Builder for the creation of {@link FlatXmlDataSet} instances.
38 *
39 * @see FlatXmlDataSet
40 * @author gommma (gommma AT users.sourceforge.net)
41 * @author Last changed by: $Author: gommma $
42 * @version $Revision: 1048 $ $Date: 2009-09-26 18:21:40 +0200 (sab, 26 set 2009) $
43 * @since 2.4.7
44 */
45 public final class FlatXmlDataSetBuilder
46 {
47 /**
48 * Logger for this class
49 */
50 private static final Logger logger = LoggerFactory.getLogger(FlatXmlDataSetBuilder.class);
51
52 /**
53 * The metadata (column information etc.) for the flat XML to be built.
54 * If this is set the builder properties
55 * <ul>
56 * <li>{@link #columnSensing}</li>
57 * <li>{@link #caseSensitiveTableNames}</li>
58 * <li>{@link #dtdMetadata}</li>
59 * </ul>
60 * are <b>not</b> regarded.
61 */
62 private IDataSet metaDataSet = null;
63
64 /**
65 * Whether or not DTD metadata is available to parse via a DTD handler. Defaults to {@value}
66 */
67 private boolean dtdMetadata = true;
68
69 //TODO Think about this: should we use "columnSensing=true" by default if no DTD is specified? To avoid e.g. bug reports like #2812985 https://sourceforge.net/tracker/?func=detail&atid=449491&aid=2812985&group_id=47439
70 /**
71 * Since DBUnit 2.3.0 there is a functionality called "column sensing" which basically
72 * reads in the whole XML into a buffer and dynamically adds new columns as they appear.
73 * Defaults to {@value}
74 */
75 private boolean columnSensing = false;
76 /**
77 * Whether or not the created dataset should use case sensitive table names
78 * Defaults to {@value}
79 */
80 private boolean caseSensitiveTableNames = false;
81
82
83 /**
84 * Default constructor
85 */
86 public FlatXmlDataSetBuilder()
87 {
88 }
89
90 /**
91 * Sets the flat XML input source from which the {@link FlatXmlDataSet} is to be built
92 * @param inputSource The flat XML input as {@link InputSource}
93 * @return The created {@link FlatXmlDataSet}
94 * @throws DataSetException
95 */
96 public FlatXmlDataSet build(InputSource inputSource) throws DataSetException
97 {
98 return buildInternal(inputSource);
99 }
100
101 /**
102 * Sets the flat XML input source from which the {@link FlatXmlDataSet} is to be built
103 * @param xmlInputFile The flat XML input as {@link File}
104 * @return The created {@link FlatXmlDataSet}
105 * @throws DataSetException
106 */
107 public FlatXmlDataSet build(File xmlInputFile) throws MalformedURLException, DataSetException
108 {
109 URL xmlInputUrl = xmlInputFile.toURL();
110 InputSource inputSource = createInputSourceFromUrl(xmlInputUrl);
111 return buildInternal(inputSource);
112 }
113
114 /**
115 * Sets the flat XML input source from which the {@link FlatXmlDataSet} is to be built
116 * @param xmlInputUrl The flat XML input as {@link URL}
117 * @return The created {@link FlatXmlDataSet}
118 * @throws DataSetException
119 */
120 public FlatXmlDataSet build(URL xmlInputUrl) throws DataSetException
121 {
122 InputSource inputSource = createInputSourceFromUrl(xmlInputUrl);
123 return buildInternal(inputSource);
124 }
125
126 /**
127 * Sets the flat XML input source from which the {@link FlatXmlDataSet} is to be built
128 * @param xmlReader The flat XML input as {@link Reader}
129 * @return The created {@link FlatXmlDataSet}
130 * @throws DataSetException
131 */
132 public FlatXmlDataSet build(Reader xmlReader) throws DataSetException
133 {
134 InputSource inputSource = new InputSource(xmlReader);
135 return buildInternal(inputSource);
136 }
137
138 /**
139 * Sets the flat XML input source from which the {@link FlatXmlDataSet} is to be built
140 * @param xmlInputStream The flat XML input as {@link InputStream}
141 * @return The created {@link FlatXmlDataSet}
142 * @throws DataSetException
143 */
144 public FlatXmlDataSet build(InputStream xmlInputStream) throws DataSetException
145 {
146 InputSource inputSource = new InputSource(xmlInputStream);
147 return buildInternal(inputSource);
148 }
149
150 /**
151 * Utility method to create an {@link InputSource} object from a URL
152 * @param xmlInputUrl
153 * @return
154 */
155 private InputSource createInputSourceFromUrl(URL xmlInputUrl)
156 {
157 String stringUrl = xmlInputUrl.toString();
158 return new InputSource(stringUrl);
159 }
160
161 /**
162 * Set the metadata information (column info etc.) to be used. May come from a DTD.
163 * This has precedence to the other builder's properties.
164 * @param metaDataSet
165 * @return this
166 */
167 public FlatXmlDataSetBuilder setMetaDataSet(IDataSet metaDataSet)
168 {
169 this.metaDataSet = metaDataSet;
170 return this;
171 }
172
173 /**
174 * Set the metadata information (column info etc.) to be used from the given DTD input.
175 * This has precedence to the other builder's properties.
176 * @param dtdReader A reader that provides the DTD content
177 * @throws DataSetException
178 * @throws IOException
179 * @return this
180 */
181 public FlatXmlDataSetBuilder setMetaDataSetFromDtd(Reader dtdReader) throws DataSetException, IOException
182 {
183 this.metaDataSet = new FlatDtdDataSet(dtdReader);
184 return this;
185 }
186
187 /**
188 * Set the metadata information (column info etc.) to be used from the given DTD input.
189 * This has precedence to the other builder's properties.
190 * @param dtdStream
191 * @throws DataSetException
192 * @throws IOException
193 * @return this
194 */
195 public FlatXmlDataSetBuilder setMetaDataSetFromDtd(InputStream dtdStream) throws DataSetException, IOException
196 {
197 this.metaDataSet = new FlatDtdDataSet(dtdStream);
198 return this;
199 }
200
201 public boolean isDtdMetadata() {
202 return dtdMetadata;
203 }
204
205 /**
206 * Whether or not DTD metadata is available to parse via a DTD handler.
207 * @param dtdMetadata
208 * @return this
209 */
210 public FlatXmlDataSetBuilder setDtdMetadata(boolean dtdMetadata) {
211 this.dtdMetadata = dtdMetadata;
212 return this;
213 }
214
215 public boolean isColumnSensing() {
216 return columnSensing;
217 }
218
219 /**
220 * Since DBUnit 2.3.0 there is a functionality called "column sensing" which basically
221 * reads in the whole XML into a buffer and dynamically adds new columns as they appear.
222 * @param columnSensing
223 * @return this
224 */
225 public FlatXmlDataSetBuilder setColumnSensing(boolean columnSensing) {
226 this.columnSensing = columnSensing;
227 return this;
228 }
229
230 public boolean isCaseSensitiveTableNames() {
231 return caseSensitiveTableNames;
232 }
233
234 /**
235 * Whether or not the created dataset should use case sensitive table names
236 * @param caseSensitiveTableNames
237 * @return this
238 */
239 public FlatXmlDataSetBuilder setCaseSensitiveTableNames(boolean caseSensitiveTableNames) {
240 this.caseSensitiveTableNames = caseSensitiveTableNames;
241 return this;
242 }
243
244
245 /**
246 * Builds the {@link FlatXmlDataSet} from the parameters that are currently set on this builder
247 * @param inputSource The XML input to be built
248 * @return The {@link FlatXmlDataSet} built from the configuration of this builder.
249 * @throws DataSetException
250 */
251 private FlatXmlDataSet buildInternal(InputSource inputSource) throws DataSetException
252 {
253 logger.trace("build(inputSource={}) - start", inputSource);
254
255 // Validate required parameters
256 if(inputSource==null)
257 {
258 throw new NullPointerException("The parameter 'inputSource' must not be null");
259 }
260
261 // Create the flat XML IDataSet
262 logger.debug("Creating FlatXmlDataSet with builder parameters: {}", this);
263 FlatXmlProducer producer = createProducer(inputSource);
264 return new FlatXmlDataSet(producer);
265 }
266
267 /**
268 * @param inputSource The XML input to be built
269 * @return The producer which is used to create the {@link FlatXmlDataSet}
270 */
271 protected FlatXmlProducer createProducer(InputSource inputSource)
272 {
273 logger.trace("createProducer(inputSource={}) - start", inputSource);
274
275 FlatXmlProducer producer = null;
276 if(this.metaDataSet!=null)
277 {
278 logger.debug("Creating FlatXmlProducer using the following metaDataSet: {}", this.metaDataSet);
279 producer = new FlatXmlProducer(inputSource, this.metaDataSet);
280 }
281 else
282 {
283 logger.debug("Creating FlatXmlProducer using the properties of this builder: {}", this);
284 producer = new FlatXmlProducer(
285 inputSource, this.dtdMetadata, this.columnSensing, this.caseSensitiveTableNames);
286 }
287 return producer;
288 }
289
290 public String toString()
291 {
292 StringBuffer sb = new StringBuffer();
293 sb.append(getClass().getName()).append("[");
294 sb.append("dtdMetadata=").append(dtdMetadata);
295 sb.append(", columnSensing=").append(columnSensing);
296 sb.append(", caseSensitiveTableNames=").append(caseSensitiveTableNames);
297 sb.append(", metaDataSet=").append(metaDataSet);
298 sb.append("]");
299 return sb.toString();
300 }
301 }