View Javadoc
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$
42   * @version $Revision$ $Date$
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 }