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