/
JdbcDataStoreConfiguration.java
473 lines (417 loc) · 21.6 KB
/
JdbcDataStoreConfiguration.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/*******************************************************************************
* Copyright (c) 2013 uniVocity Software Pty Ltd. All rights reserved.
* This file is subject to the terms and conditions defined in file
* 'LICENSE.txt', which is part of this source code package.
******************************************************************************/
package com.univocity.api.entity.jdbc;
import java.io.*;
import java.nio.charset.*;
import java.sql.*;
import java.util.*;
import javax.sql.*;
import com.univocity.api.common.*;
import com.univocity.api.engine.*;
import com.univocity.api.entity.custom.*;
/**
* The JDBC data store configuration class. Use it to configure the JDBC data entities and queries that will be manipulated by a {@link DataIntegrationEngine}.
*
* @see JdbcEntityConfiguration
* @see JdbcQueryConfiguration
* @see DataSource
*
* @author uniVocity Software Pty Ltd - <a href="mailto:dev@univocity.com">dev@univocity.com</a>
*/
public final class JdbcDataStoreConfiguration extends DataStoreConfiguration {
private final DataSource dataSource;
private final JdbcEntityConfiguration defaultEntityConfiguration = new JdbcEntityConfiguration();
private final JdbcQueryConfiguration defaultQueryConfiguration = new JdbcQueryConfiguration();
final Map<String, JdbcEntityConfiguration> tableConfigurations = new TreeMap<String, JdbcEntityConfiguration>();
final Map<String, JdbcQueryConfiguration> queryConfigurations = new TreeMap<String, JdbcQueryConfiguration>();
private String schema;
private String catalog;
private DatabaseDialect dialect;
private int transactionTimeout = -1;
private int transactionIsolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
private DatabaseCapabilities databaseInformation = null;
private final Collection<String> reservedWordsToEscape = new TreeSet<String>();
private IdentifierEscaper identifierEscaper = null;
/**
* Creates a new JDBC data store configuration
* @param dataStoreName the name of the JDBC data store.
* @param dataSource the {@code DataSource} used to connect to the underlying database.
*/
public JdbcDataStoreConfiguration(String dataStoreName, DataSource dataSource) {
super(dataStoreName);
if (dataSource == null) {
throw new IllegalArgumentException("Datasource cannot be null");
}
this.dataSource = dataSource;
}
/**
* Obtains the DataSource used to connect to the managed JDBC data entities.
* @return the DataSource
*/
public final DataSource getDataSource() {
return dataSource;
}
/**
* Obtains the schema name that should be used to refer to elements of the database managed by this JDBC data store.
* @return the schema
*/
public final String getSchema() {
return schema;
}
/**
* Defines the schema name that should be used to refer to elements of the database managed by this JDBC data store.
* @param schema the schema name
*/
public final void setSchema(String schema) {
this.schema = schema;
}
/**
* Obtains the catalog name that should be used to refer to elements of the database managed by this JDBC data store.
* @return the catalog
*/
public final String getCatalog() {
return catalog;
}
/**
* Defines the catalog name that should be used to refer to elements of the database managed by this JDBC data store.
* @param catalog the catalog name
*/
public final void setCatalog(String catalog) {
this.catalog = catalog;
}
/**
* Obtains an object describing the capabilities of the database managed by this JDBC data store.
* <p><i>By default, uniVocity tries to detect this information automatically.</i>
* @return the database capabilities information
*/
public final DatabaseCapabilities getDatabaseInformation() {
return databaseInformation;
}
/**
* Defines the capabilities of the database managed by this JDBC data store.
* <p><i>By default, uniVocity tries to detect this information automatically. The configuration you set here takes precedence over any auto-detected data.</i>
* @param databaseInformation the database information.
*/
public final void setDatabaseInformation(DatabaseCapabilities databaseInformation) {
Args.notNull(databaseInformation, "Database capabilities object");
this.databaseInformation = databaseInformation;
}
/**
* Returns the configuration of a given data entity. The returned configuration object will contain default values provided in the object returned by {@link #getDefaultEntityConfiguration()}.
* <br>If the entity was not explicitly configured before, a new configuration object will be created and associated with the entity.
* <p>You can change the default configuration at any time by calling {@link #getDefaultEntityConfiguration()} and altering the settings you need.
* Subsequent calls to {@link #getEntityConfiguration(String)} will return a configuration object with the new defaults.
* Existing configurations will retain their original values, including the default settings previously used.
* @param tableName the name of the entity to be configured
* @return a configuration object for the given data entity.
*/
public final JdbcEntityConfiguration getEntityConfiguration(String tableName) {
Args.notBlank(tableName, "Table name");
JdbcEntityConfiguration out = tableConfigurations.get(tableName);
if (out == null) {
out = new JdbcEntityConfiguration();
tableConfigurations.put(tableName, out);
}
out.copyDefaultsFrom(defaultEntityConfiguration);
return out;
}
/**
* Returns the default configuration object for JDBC data entities.
* This object returns all default values used for creating new configuration objects for data entities.
* @return the {@link #defaultEntityConfiguration} object.
*/
public final JdbcEntityConfiguration getDefaultEntityConfiguration() {
return defaultEntityConfiguration;
}
/**
* Returns the default configuration object for JDBC query entities.
* This object returns all default values used for creating new configuration objects for query entities.
* @return the {@link #defaultQueryConfiguration} object.
*/
public final JdbcQueryConfiguration getDefaultQueryConfiguration() {
return defaultQueryConfiguration;
}
/**
* Creates a new SQL query entity from a resource and adds it to this data store. The resource path can be a file in the class path or in the file system.
* @param queryName the name of the query
* @param resourcePath the path to a resource that contains an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* <p><i><b>Note: </b>As the resource encoding is not provided, the default system encoding will be used.</i>
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQueryFromResource(String queryName, String resourcePath) {
return addQuery(queryName, new FileProvider(resourcePath));
}
/**
* Creates a new SQL query entity from a resource and adds it to this data store. The resource path can be a file in the class path or in the file system.
* @param queryName the name of the query
* @param resourcePath the path to a resource that contains an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the encoding of the resource
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQueryFromResource(String queryName, String resourcePath, String encoding) {
return addQuery(queryName, new FileProvider(resourcePath, encoding));
}
/**
* Creates a new SQL query entity from a resource and adds it to this data store. The resource path can be a file in the class path or in the file system.
* @param name queryName the name of the query
* @param resourcePath the path to a resource that contains an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the encoding of the resource
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQueryFromResource(String name, String resourcePath, Charset encoding) {
return addQuery(name, new FileProvider(resourcePath, encoding));
}
/**
* Creates a new SQL query entity from a file and adds it to this data store. The file name will be used as the query name.
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* <p><i><b>Note: </b>As the encoding of the query file is not provided, the default system encoding will be used.</i>
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(File queryFile) {
return addQuery(queryFile, (Charset) null);
}
/**
* Creates a new SQL query entity from a file and adds it to this data store. The file name will be used as the query name.
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the file encoding
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(File queryFile, String encoding) {
Args.validFile(queryFile, "Query file");
return addQuery(getQueryNameFromFile(queryFile), new FileProvider(queryFile, encoding));
}
/**
* Creates a new SQL query entity from a file and adds it to this data store. The file name will be used as the query name.
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the file encoding
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(File queryFile, Charset encoding) {
Args.validFile(queryFile, "Query file");
return addQuery(getQueryNameFromFile(queryFile), new FileProvider(queryFile, encoding));
}
private String getQueryNameFromFile(File queryFile) {
String name = queryFile.getName();
int lastDot = name.lastIndexOf('.');
if (lastDot != -1) {
return name.substring(0, lastDot);
}
return name;
}
/**
* Creates a new SQL query entity from a file and adds it to this data store.
* @param queryName the name of the query
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* <p><i><b>Note: </b>As the encoding of the query file is not provided, the default system encoding will be used.</i>
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(String queryName, File queryFile) {
return addQuery(queryName, new FileProvider(queryFile));
}
/**
* Creates a new SQL query entity from a file and adds it to this data store.
* @param queryName the name of the query
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the file encoding
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(String queryName, File queryFile, String encoding) {
Args.validFile(queryFile, "Query file");
return addQuery(queryName, new FileProvider(queryFile, encoding));
}
/**
* Creates a new SQL query entity from a file and adds it to this data store.
* @param queryName the name of the query
* @param queryFile a text file containing an SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @param encoding the file encoding
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(String queryName, File queryFile, Charset encoding) {
Args.validFile(queryFile, "Query file");
return addQuery(queryName, new FileProvider(queryFile, encoding));
}
/**
* Creates a new SQL query entity and adds it to this data store.
* @param queryName the name of the query
* @param query the SQL query. Parameters must be prefixed with a colon, for example: <i>SELECT col_1, col2 FROM table WHERE col_1 = <b>:param_1</b> OR col_2 = <b>:param_2</b></i>
* @return a configuration object for the new query.
*/
public final JdbcQueryConfiguration addQuery(String queryName, String query) {
return addQuery(queryName, new JdbcQueryConfiguration(query));
}
private JdbcQueryConfiguration addQuery(String queryName, FileProvider fileProvider) {
return addQuery(queryName, new JdbcQueryConfiguration(fileProvider));
}
private JdbcQueryConfiguration addQuery(String queryName, JdbcQueryConfiguration config) {
Args.notBlank(queryName, "Query name");
String key = queryName.trim();
if (queryConfigurations.containsKey(key)) {
throw new IllegalArgumentException("Duplicate query name: " + key);
}
queryConfigurations.put(key, config);
return config;
}
/**
* Returns the configuration of a given query entity. The returned configuration object will contain default values provided in the object returned by {@link #getDefaultQueryConfiguration()}.
* <br>If the query was not explicitly configured before, a new configuration object will be created and associated with it.
* <p>You can change the default configuration at any time by calling {@link #getDefaultQueryConfiguration()} and altering the settings you need.
* Subsequent calls to {@link #getQueryConfiguration(String)} will return a configuration object with the new defaults.
* Existing configurations will retain their original values, including the default settings previously used.
* @param queryName the name of the query to be configured
* @return a configuration object for the given query entity.
*/
public final JdbcQueryConfiguration getQueryConfiguration(String queryName) {
Args.notBlank(queryName, "Query name");
queryName = queryName.trim();
if (!queryConfigurations.containsKey(queryName)) {
throw new IllegalArgumentException("Cannot find query with name: " + queryName);
}
JdbcQueryConfiguration out = queryConfigurations.get(queryName);
out.copyDefaultsFrom(defaultQueryConfiguration);
return out;
}
/**
* Obtains the timeout, in number of seconds, for transactions created from this data store.
* <p>Transactions will be created automatically by uniVocity while performing data mapping operations to this data store.
* <br>A new transaction will be created for each mapping cycle started with {@link DataIntegrationEngine#executeCycle()}.
* <p><i>Defaults to -1 (no timeout)</i>
* @return the transaction timeout.
*/
public final int getTransactionTimeout() {
return transactionTimeout;
}
/**
* Defines a timeout, in number of seconds, for transactions created from this data store.
* <p>Transactions will be created automatically by uniVocity while performing data mapping operations to this data store.
* <br>A new transaction will be created for each mapping cycle started with {@link DataIntegrationEngine#executeCycle()}.
* @param transactionTimeout the transaction timeout.
*/
public final void setTransactionTimeout(int transactionTimeout) {
Args.positive(transactionTimeout, "Transaction timeout");
this.transactionTimeout = transactionTimeout;
}
/**
* Obtains the transaction isolation level used when persisting data into entities of this data store.
* <br>The transaction isolation level code returned by this method is passed on
* to {@link java.sql.Connection#setTransactionIsolation(int)} before mapping data to an entity.
* <p><i>Defaults to {@link java.sql.Connection#TRANSACTION_REPEATABLE_READ}</i></p>
* @return the transaction isolation level
*/
public final int getTransactionIsolationLevel() {
return transactionIsolationLevel;
}
/**
* Defines the transaction isolation level used when persisting data into entities of this data store.
* <br>The transaction isolation level code returned by this method is passed on
* to {@link java.sql.Connection#setTransactionIsolation(int)} before mapping data to an entity.
* <p><i>Only the constants defined in {@link java.sql.Connection} are accepted.</i></p>
* @param transactionIsolationLevel the transaction isolation level
*/
public final void setTransactionIsolationLevel(int transactionIsolationLevel) {
Args.validTransactionIsolationLevel(transactionIsolationLevel);
this.transactionIsolationLevel = transactionIsolationLevel;
}
/**
* Obtains the maximum number of rows loaded in memory at a time when extracting information from entities and queries in this data store.
* <p>This number is obtained from default fetch size in {@link #getDefaultEntityConfiguration()}.
* <p><i>Defaults to 10,000 rows</i>
* @return the maximum number of rows kept in memory at any given time when reading values from any entity or query of this data store.
*/
@Override
public final int getLimitOfRowsLoadedInMemory() {
return defaultEntityConfiguration.getFetchSize();
}
/**
* Defines the maximum number of rows loaded in memory at a time when extracting information from entities and queries in this data store.
* <p>This number modifies the default fetch size in {@link #getDefaultEntityConfiguration()} and {@link #getDefaultQueryConfiguration()}.
* <br>The fetch size of already configured entities and queries won't be modified.
* @param rowLimit the maximum number of rows kept in memory at any given time when reading values from any entity or query of this data store.
*/
public final void setLimitOfRowsLoadedInMemory(int rowLimit) {
this.defaultEntityConfiguration.setFetchSize(rowLimit);
this.defaultQueryConfiguration.setFetchSize(rowLimit);
}
/**
* Adds user-defined reserved words that might conflict with table and column names in SQL statements.
* <p>When generating SQL, an {@link IdentifierEscaper} will handle name conflicts and escape any table or column names that are part of potential reserved words.
* <p>uniVocity already escapes most common reserved words used by different database vendors. Use this method to provide any additional reserved words.
* @param reservedWords additional reserved words to escape.
*/
public final void addReservedWordsToEscape(String... reservedWords) {
Args.notEmpty(reservedWords, "Reserved words");
for (String reservedWord : reservedWords) {
this.reservedWordsToEscape.add(reservedWord);
}
}
/**
* Adds user-defined reserved words that might conflict with table and column names in SQL statements.
* <p>When generating SQL, an {@link IdentifierEscaper} will handle name conflicts and escape any table or column names that are part of potential reserved words.
* <p>uniVocity already escapes most common reserved words used by different database vendors. Use this method to provide any additional reserved words.
* @param reservedWords additional reserved words to escape.
*/
public final void addReservedWordsToEscape(Collection<String> reservedWords) {
Args.notEmpty(reservedWords, "Reserved words");
for (String reservedWord : reservedWords) {
this.reservedWordsToEscape.add(reservedWord);
}
}
/**
* Returns the collection of user-defined reserved words provided with {@link #addReservedWordsToEscape(String...)}.
* @return an unmodifiable collection of reserved words.
*/
public final Collection<String> getReservedWordsToEscape() {
return Collections.unmodifiableCollection(reservedWordsToEscape);
}
/**
* Provides a user-defined {@link IdentifierEscaper} to handle reserved word escaping when generating SQL statements.
* <p> This will override uniVocity's default implementation that escapes reserved words by enclosing them within double quotes(e.g. "escaped identifier").
* @param escape a custom implementation of {@link IdentifierEscaper}
*/
public final void setIdentifierEscaper(IdentifierEscaper escape) {
Args.notNull(escape, "Implementation of com.univocity.api.entity.jdbc.IdentifierEscaper");
this.identifierEscaper = escape;
}
/**
* Returns the user-defined {@link IdentifierEscaper} configured to handle reserved word escaping when SQL statements are generated.
* @return a custom implementation of {@link IdentifierEscaper}, or {@code null} if uniVocity's default implementation should be used.
*/
public final IdentifierEscaper getIdentifierEscaper() {
return this.identifierEscaper;
}
/**
* Has no effect over JDBC data entities as they already support database operations.
*/
@Override
public final void enableDatabaseOperationsIn(String... tableNames) {
}
/**
* Has no effect over JDBC data entities as they already support database operations.
*/
@Override
public final void enableDatabaseOperationsIn(Collection<String> entityNames) {
}
/**
* Returns an empty set as JDBC data entities already support database operations.
*/
@Override
public final Set<String> getDatabaseEnabledEntities() {
return Collections.emptySet();
}
/**
* Returns the dialect of this database. Used to generate entities (tables) dynamically when required.
* @return the dialect of this database.
*/
public DatabaseDialect getDialect() {
return dialect;
}
/**
* Defines the dialect of this database. Used to generate entities (tables) dynamically when required.
* @param dialect the dialect of this database.
*/
public void setDialect(DatabaseDialect dialect) {
this.dialect = dialect;
}
}