1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit.database;
22
23 import java.sql.SQLException;
24 import java.sql.Statement;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.Properties;
29
30 import org.dbunit.DatabaseUnitException;
31 import org.dbunit.database.statement.IStatementFactory;
32 import org.dbunit.database.statement.PreparedStatementFactory;
33 import org.dbunit.dataset.datatype.DefaultDataTypeFactory;
34 import org.dbunit.dataset.datatype.IDataTypeFactory;
35 import org.dbunit.dataset.filter.IColumnFilter;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44
45
46
47
48 public class DatabaseConfig
49 {
50
51
52
53
54 private static final Logger logger = LoggerFactory.getLogger(DatabaseConfig.class);
55
56 public static final String PROPERTY_STATEMENT_FACTORY =
57 "http://www.dbunit.org/properties/statementFactory";
58 public static final String PROPERTY_RESULTSET_TABLE_FACTORY =
59 "http://www.dbunit.org/properties/resultSetTableFactory";
60 public static final String PROPERTY_DATATYPE_FACTORY =
61 "http://www.dbunit.org/properties/datatypeFactory";
62 public static final String PROPERTY_ESCAPE_PATTERN =
63 "http://www.dbunit.org/properties/escapePattern";
64 public static final String PROPERTY_TABLE_TYPE =
65 "http://www.dbunit.org/properties/tableType";
66 public static final String PROPERTY_PRIMARY_KEY_FILTER =
67 "http://www.dbunit.org/properties/primaryKeyFilter";
68 public static final String PROPERTY_BATCH_SIZE =
69 "http://www.dbunit.org/properties/batchSize";
70 public static final String PROPERTY_FETCH_SIZE =
71 "http://www.dbunit.org/properties/fetchSize";
72 public static final String PROPERTY_METADATA_HANDLER =
73 "http://www.dbunit.org/properties/metadataHandler";
74 public static final String PROPERTY_ALLOW_VERIFYTABLEDEFINITION_EXPECTEDTABLE_COUNT_MISMATCH =
75 "http://www.dbunit.org/properties/allowVerifytabledefinitionExpectedtableCountMismatch";
76 public static final String PROPERTY_IDENTITY_COLUMN_FILTER =
77 "http://www.dbunit.org/properties/mssql/identityColumnFilter";
78
79 public static final String FEATURE_CASE_SENSITIVE_TABLE_NAMES =
80 "http://www.dbunit.org/features/caseSensitiveTableNames";
81 public static final String FEATURE_QUALIFIED_TABLE_NAMES =
82 "http://www.dbunit.org/features/qualifiedTableNames";
83 public static final String FEATURE_BATCHED_STATEMENTS =
84 "http://www.dbunit.org/features/batchedStatements";
85 public static final String FEATURE_DATATYPE_WARNING =
86 "http://www.dbunit.org/features/datatypeWarning";
87 public static final String FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES =
88 "http://www.dbunit.org/features/skipOracleRecycleBinTables";
89 public static final String FEATURE_ALLOW_EMPTY_FIELDS =
90 "http://www.dbunit.org/features/allowEmptyFields";
91
92
93
94
95
96 public static final ConfigProperty[] ALL_PROPERTIES = new ConfigProperty[] {
97 new ConfigProperty(PROPERTY_STATEMENT_FACTORY, IStatementFactory.class, false),
98 new ConfigProperty(PROPERTY_RESULTSET_TABLE_FACTORY, IResultSetTableFactory.class, false),
99 new ConfigProperty(PROPERTY_DATATYPE_FACTORY, IDataTypeFactory.class, false),
100 new ConfigProperty(PROPERTY_ESCAPE_PATTERN, String.class, true),
101 new ConfigProperty(PROPERTY_TABLE_TYPE, String[].class, false),
102 new ConfigProperty(PROPERTY_PRIMARY_KEY_FILTER, IColumnFilter.class, true),
103 new ConfigProperty(PROPERTY_BATCH_SIZE, Integer.class, false),
104 new ConfigProperty(PROPERTY_FETCH_SIZE, Integer.class, false),
105 new ConfigProperty(PROPERTY_METADATA_HANDLER, IMetadataHandler.class, false),
106 new ConfigProperty(PROPERTY_IDENTITY_COLUMN_FILTER, IColumnFilter.class, true),
107 new ConfigProperty(FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.class, false),
108 new ConfigProperty(FEATURE_QUALIFIED_TABLE_NAMES, Boolean.class, false),
109 new ConfigProperty(FEATURE_BATCHED_STATEMENTS, Boolean.class, false),
110 new ConfigProperty(FEATURE_DATATYPE_WARNING, Boolean.class, false),
111 new ConfigProperty(FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, Boolean.class, false),
112 new ConfigProperty(FEATURE_ALLOW_EMPTY_FIELDS, Boolean.class, false),
113 new ConfigProperty(PROPERTY_ALLOW_VERIFYTABLEDEFINITION_EXPECTEDTABLE_COUNT_MISMATCH, Boolean.class, false),
114 };
115
116
117
118
119
120 public static final String[] ALL_FEATURES = new String[] {
121 FEATURE_CASE_SENSITIVE_TABLE_NAMES,
122 FEATURE_QUALIFIED_TABLE_NAMES,
123 FEATURE_BATCHED_STATEMENTS,
124 FEATURE_DATATYPE_WARNING,
125 FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES,
126 FEATURE_ALLOW_EMPTY_FIELDS
127 };
128
129 private static final DefaultDataTypeFactory DEFAULT_DATA_TYPE_FACTORY =
130 new DefaultDataTypeFactory();
131 private static final PreparedStatementFactory PREPARED_STATEMENT_FACTORY =
132 new PreparedStatementFactory();
133 private static final CachedResultSetTableFactory RESULT_SET_TABLE_FACTORY =
134 new CachedResultSetTableFactory();
135 private static final String DEFAULT_ESCAPE_PATTERN = null;
136 private static final String[] DEFAULT_TABLE_TYPE = {"TABLE"};
137 private static final Integer DEFAULT_BATCH_SIZE = 100;
138 private static final Integer DEFAULT_FETCH_SIZE = 100;
139
140
141
142 private Map _propertyMap = new HashMap();
143
144 private final Configurator configurator;
145
146 public DatabaseConfig()
147 {
148 setFeature(FEATURE_BATCHED_STATEMENTS, false);
149 setFeature(FEATURE_QUALIFIED_TABLE_NAMES, false);
150 setFeature(FEATURE_CASE_SENSITIVE_TABLE_NAMES, false);
151 setFeature(FEATURE_DATATYPE_WARNING, true);
152 setFeature(FEATURE_ALLOW_EMPTY_FIELDS, false);
153
154 setProperty(PROPERTY_STATEMENT_FACTORY, PREPARED_STATEMENT_FACTORY);
155 setProperty(PROPERTY_RESULTSET_TABLE_FACTORY, RESULT_SET_TABLE_FACTORY);
156 setProperty(PROPERTY_DATATYPE_FACTORY, DEFAULT_DATA_TYPE_FACTORY);
157 setProperty(PROPERTY_ESCAPE_PATTERN, DEFAULT_ESCAPE_PATTERN);
158 setProperty(PROPERTY_TABLE_TYPE, DEFAULT_TABLE_TYPE);
159 setProperty(PROPERTY_BATCH_SIZE, DEFAULT_BATCH_SIZE);
160 setProperty(PROPERTY_FETCH_SIZE, DEFAULT_FETCH_SIZE);
161 setProperty(PROPERTY_METADATA_HANDLER, new DefaultMetadataHandler());
162 setProperty(
163 PROPERTY_ALLOW_VERIFYTABLEDEFINITION_EXPECTEDTABLE_COUNT_MISMATCH,
164 Boolean.FALSE);
165
166 this.configurator = new Configurator(this);
167 }
168
169
170
171
172 protected Configurator getConfigurator()
173 {
174 return configurator;
175 }
176
177
178
179
180
181
182
183
184 public void setFeature(String name, boolean value)
185 {
186 logger.trace("setFeature(name={}, value={}) - start", name, String.valueOf(value));
187
188 setProperty(name, Boolean.valueOf(value));
189 }
190
191
192
193
194
195
196
197
198 public boolean getFeature(String name)
199 {
200 logger.trace("getFeature(name={}) - start", name);
201
202 Object property = getProperty(name);
203 if(property == null)
204 {
205 return false;
206 }
207 else if(property instanceof Boolean)
208 {
209 Boolean feature = (Boolean) property;
210 return feature.booleanValue();
211 }
212 else
213 {
214 String propString = String.valueOf(property);
215 Boolean feature = Boolean.valueOf(propString);
216 return feature.booleanValue();
217 }
218 }
219
220
221
222
223
224
225
226 public void setProperty(String name, Object value)
227 {
228 logger.trace("setProperty(name={}, value={}) - start", name, value);
229
230 value = convertIfNeeded(name, value);
231
232
233 checkObjectAllowed(name, value);
234
235
236 _propertyMap.put(name, value);
237 }
238
239
240
241
242
243
244
245 public Object getProperty(String name)
246 {
247 logger.trace("getProperty(name={}) - start", name);
248
249 return _propertyMap.get(name);
250 }
251
252 private Object convertIfNeeded(String property, Object value)
253 {
254 logger.trace("convertIfNeeded(property={}, value={}) - start", property, value);
255
256 ConfigProperty prop = findByName(property);
257 if(prop==null) {
258 throw new IllegalArgumentException("Did not find property with name '" + property + "'");
259 }
260 Class allowedPropType = prop.getPropertyType();
261
262 if(allowedPropType == Boolean.class || allowedPropType == boolean.class)
263 {
264
265 if(value instanceof String)
266 {
267 return Boolean.valueOf((String)value);
268 }
269 }
270
271 return value;
272 }
273
274
275
276
277
278
279
280 protected void checkObjectAllowed(String property, Object value)
281 {
282 logger.trace("checkObjectAllowed(property={}, value={}) - start", property, value);
283
284 ConfigProperty prop = findByName(property);
285
286 if(prop != null)
287 {
288
289 if(value == null)
290 {
291 if(prop.isNullable())
292 {
293
294 return;
295 }
296 else
297 {
298 throw new IllegalArgumentException("The property '" + property + "' is not nullable.");
299 }
300 }
301 else
302 {
303 Class allowedPropType = prop.getPropertyType();
304 if(!allowedPropType.isAssignableFrom(value.getClass()))
305 {
306 throw new IllegalArgumentException("Cannot cast object of type '" + value.getClass() +
307 "' to allowed type '" + allowedPropType + "'.");
308 }
309 }
310 }
311 else
312 {
313 logger.info("Unknown property '" + property + "'. Cannot validate the type of the object to be set." +
314 " Please notify a developer to update the list of properties.");
315 }
316 }
317
318
319
320
321
322
323
324
325
326
327 public void setPropertiesByString(Properties stringProperties) throws DatabaseUnitException
328 {
329 for (Iterator iterator = stringProperties.entrySet().iterator(); iterator.hasNext();) {
330 Map.Entry entry = (Map.Entry) iterator.next();
331
332 String propKey = (String)entry.getKey();
333 String propValue = (String)entry.getValue();
334
335 ConfigProperty dbunitProp = DatabaseConfig.findByName(propKey);
336 if(dbunitProp == null)
337 {
338 logger.debug("Did not find long name property {} - trying short name...", entry);
339 dbunitProp = DatabaseConfig.findByShortName(propKey);
340 }
341
342 if(dbunitProp == null)
343 {
344 logger.info("Could not set property '{}' - not found in the list of known properties.", entry);
345 }
346 else
347 {
348 String fullPropName = dbunitProp.getProperty();
349 Object obj = createObjectFromString(dbunitProp, propValue);
350 this.setProperty(fullPropName, obj);
351 }
352 }
353 }
354
355 private Object createObjectFromString(ConfigProperty dbunitProp, String propValue)
356 throws DatabaseUnitException
357 {
358 if (dbunitProp == null) {
359 throw new NullPointerException(
360 "The parameter 'dbunitProp' must not be null");
361 }
362 if (propValue == null) {
363
364 return null;
365 }
366
367 Class targetClass = dbunitProp.getPropertyType();
368 if(targetClass == String.class)
369 {
370 return propValue;
371 }
372 else if(targetClass == Boolean.class)
373 {
374 return Boolean.valueOf(propValue);
375 }
376 else if(targetClass == String[].class)
377 {
378 String[] result = propValue.split(",");
379 for (int i = 0; i < result.length; i++) {
380 result[i] = result[i].trim();
381 }
382 return result;
383 }
384 else if(targetClass == Integer.class)
385 {
386 return new Integer(propValue);
387 }
388 else
389 {
390
391 return createInstance(propValue);
392 }
393 }
394
395 private Object createInstance(String className) throws DatabaseUnitException
396 {
397
398 try
399 {
400 Object o = Class.forName(className).newInstance();
401 return o;
402 }
403 catch (ClassNotFoundException e)
404 {
405 throw new DatabaseUnitException(
406 "Class Not Found: '" + className + "' could not be loaded", e);
407 }
408 catch (IllegalAccessException e)
409 {
410 throw new DatabaseUnitException(
411 "Illegal Access: '" + className + "' could not be loaded", e);
412 }
413 catch (InstantiationException e)
414 {
415 throw new DatabaseUnitException(
416 "Instantiation Exception: '" + className + "' could not be loaded", e);
417 }
418 }
419
420
421
422
423
424
425 public static final ConfigProperty findByName(String property)
426 {
427 for (int i = 0; i < ALL_PROPERTIES.length; i++) {
428 if(ALL_PROPERTIES[i].getProperty().equals(property))
429 {
430 return ALL_PROPERTIES[i];
431 }
432 }
433
434 return null;
435 }
436
437
438
439
440
441
442
443
444 public static final ConfigProperty findByShortName(String propShortName)
445 {
446 for (int i = 0; i < DatabaseConfig.ALL_PROPERTIES.length; i++) {
447 String fullProperty = DatabaseConfig.ALL_PROPERTIES[i].getProperty();
448 if(fullProperty.endsWith(propShortName))
449 {
450 return DatabaseConfig.ALL_PROPERTIES[i];
451 }
452 }
453
454 logger.info("The property ending with '" + propShortName + "' was not found. " +
455 "Please notify a dbunit developer to add the property to the " + DatabaseConfig.class);
456 return null;
457 }
458
459 public String toString()
460 {
461 final StringBuilder sb = new StringBuilder();
462 sb.append(getClass().getName()).append("[");
463 sb.append(", _propertyMap=").append(_propertyMap);
464 sb.append("]");
465 return sb.toString();
466 }
467
468
469
470
471
472
473
474
475
476
477 public static class ConfigProperty
478 {
479 private String property;
480 private Class propertyType;
481 private boolean nullable;
482
483 public ConfigProperty(String property, Class propertyType, boolean nullable) {
484 super();
485
486 if (property == null) {
487 throw new NullPointerException(
488 "The parameter 'property' must not be null");
489 }
490 if (propertyType == null) {
491 throw new NullPointerException(
492 "The parameter 'propertyType' must not be null");
493 }
494
495 this.property = property;
496 this.propertyType = propertyType;
497 this.nullable = nullable;
498 }
499
500 public String getProperty() {
501 return property;
502 }
503
504 public Class getPropertyType() {
505 return propertyType;
506 }
507
508 public boolean isNullable() {
509 return nullable;
510 }
511
512 public int hashCode() {
513 final int prime = 31;
514 int result = 1;
515 result = prime * result
516 + ((property == null) ? 0 : property.hashCode());
517 return result;
518 }
519
520 public boolean equals(Object obj) {
521 if (this == obj)
522 return true;
523 if (obj == null)
524 return false;
525 if (getClass() != obj.getClass())
526 return false;
527 ConfigProperty other = (ConfigProperty) obj;
528 if (property == null) {
529 if (other.property != null)
530 return false;
531 } else if (!property.equals(other.property))
532 return false;
533 return true;
534 }
535
536 public String toString()
537 {
538 final StringBuilder sb = new StringBuilder();
539 sb.append(getClass().getName()).append("[");
540 sb.append("property=").append(property);
541 sb.append(", propertyType=").append(propertyType);
542 sb.append(", nullable=").append(nullable);
543 sb.append("]");
544 return sb.toString();
545 }
546 }
547
548
549
550
551
552
553
554
555
556
557
558 protected static class Configurator
559 {
560
561
562
563 private static final Logger logger = LoggerFactory.getLogger(Configurator.class);
564
565 private DatabaseConfig config;
566
567
568
569
570
571 public Configurator(DatabaseConfig config)
572 {
573 if (config == null) {
574 throw new NullPointerException(
575 "The parameter 'config' must not be null");
576 }
577 this.config = config;
578 }
579
580
581
582
583
584
585 void configureStatement(Statement stmt) throws SQLException
586 {
587 logger.trace("configureStatement(stmt={}) - start", stmt);
588 Integer fetchSize = (Integer) config.getProperty(DatabaseConfig.PROPERTY_FETCH_SIZE);
589 stmt.setFetchSize(fetchSize.intValue());
590 logger.debug("Statement fetch size set to {}",fetchSize);
591 }
592
593 }
594
595 }