1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.spi.config.ds;
17
18 import java.io.PrintStream;
19 import java.sql.Connection;
20 import java.sql.PreparedStatement;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.sql.Statement;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28
29 import org.apache.commons.lang.StringUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import de.smartics.util.lang.Arg;
34
35
36
37
38 public class DefaultDataSourceManager extends AbstractDataSourceDescriptor
39 implements PropertiesDataSourceManager
40 {
41
42
43
44
45
46
47
48 private static final long serialVersionUID = 1L;
49
50
51
52
53 private static final Logger LOG = LoggerFactory
54 .getLogger(DefaultDataSourceManager.class);
55
56
57
58
59
60
61
62
63 private final DataSourceProxy dataSourceProxy;
64
65
66
67
68
69
70 private final Map<String, Map<String, String>> initialProperties;
71
72
73
74
75
76
77 protected final boolean dropTable;
78
79
80
81
82
83
84
85
86 protected final boolean ignoreTableCreationProblems;
87
88
89
90
91 private final String createTableSqlStatement;
92
93
94
95
96
97 private final String insertOrUpdateSqlStatementTemplate;
98
99
100
101
102
103
104
105
106
107
108 protected DefaultDataSourceManager(final Builder builder)
109 {
110 super(builder);
111
112 this.dataSourceProxy = builder.dataSourceProxy;
113 this.initialProperties = builder.initialProperties;
114 this.dropTable = builder.dropTable;
115 this.ignoreTableCreationProblems = builder.ignoreTableCreationProblems;
116 this.createTableSqlStatement =
117 filterStatement(builder.createTableSqlStatementTemplate);
118 this.insertOrUpdateSqlStatementTemplate =
119 filterStatement(builder.insertOrUpdateSqlStatementTemplate);
120 }
121
122
123
124
125
126
127 public static class Builder extends AbstractDataSourceDescriptor.Builder
128 {
129
130
131
132
133
134
135
136
137
138
139 public static final String DEFAULT_CREATE_TABLE_TEMPLATE =
140 "CREATE TABLE IF NOT EXISTS ${table}"
141 + " (${configColumn} VARCHAR(128) NOT NULL,"
142 + " ${nameColumn} VARCHAR(64) NOT NULL,"
143 + " ${valueColumn} VARCHAR(255),"
144 + " CONSTRAINT prime UNIQUE (${configColumn}, ${nameColumn}))";
145
146
147
148
149
150
151 protected DataSourceProxy dataSourceProxy;
152
153
154
155
156 private Map<String, Map<String, String>> initialProperties;
157
158
159
160
161 private boolean dropTable = true;
162
163
164
165
166
167
168 private boolean ignoreTableCreationProblems = true;
169
170
171
172
173
174
175
176
177 private String createTableSqlStatementTemplate =
178 DEFAULT_CREATE_TABLE_TEMPLATE;
179
180
181
182
183
184
185
186
187
188 protected String insertOrUpdateSqlStatementTemplate;
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 public final void setCreateTableSqlStatementTemplate(
218 final String createTableSqlStatementTemplate)
219 {
220 this.createTableSqlStatementTemplate = createTableSqlStatementTemplate;
221 }
222
223
224
225
226
227
228 public void setInsertOrUpdateSqlStatementTemplate(
229 final String insertOrUpdateSqlStatementTemplate)
230 {
231 this.insertOrUpdateSqlStatementTemplate =
232 insertOrUpdateSqlStatementTemplate;
233 }
234
235
236
237
238
239
240
241
242 public final void setDataSourceProxy(final DataSourceProxy dataSourceProxy)
243 throws NullPointerException
244 {
245 this.dataSourceProxy =
246 Arg.checkNotNull("dataSourceProxy", dataSourceProxy);
247 }
248
249
250
251
252
253
254
255 public final void setInitialProperties(
256 final Map<String, Map<String, String>> initialProperties)
257 {
258 this.initialProperties = initialProperties;
259 }
260
261
262
263
264
265
266
267
268 public final void setDropTable(final boolean dropTable)
269 {
270 this.dropTable = dropTable;
271 }
272
273
274
275
276
277
278
279
280
281 public final void setIgnoreTableCreationProblems(
282 final boolean ignoreTableCreationProblems)
283 {
284 this.ignoreTableCreationProblems = ignoreTableCreationProblems;
285 }
286
287
288
289
290
291
292
293
294
295 public DefaultDataSourceManager build() throws NullPointerException
296 {
297 Arg.checkNotNull("dataSourceProxy", dataSourceProxy);
298 Arg.checkNotNull("insertOrUpdateSqlStatementTemplate",
299 insertOrUpdateSqlStatementTemplate);
300
301 return new DefaultDataSourceManager(this);
302 }
303
304
305 }
306
307
308
309
310
311 private String filterStatement(final String template)
312 {
313 if (template == null)
314 {
315 return null;
316 }
317
318 final String sql =
319 StringUtils.replaceEach(template, new String[] { "${table}",
320 "${configColumn}",
321 "${nameColumn}",
322 "${valueColumn}" },
323 new String[] { getTable(), getConfigColumn(), getNameColumn(),
324 getValueColumn() });
325 return sql;
326 }
327
328
329
330 @Override
331 public final String getDataSourceId()
332 {
333 return dataSourceProxy.getDataSourceId();
334 }
335
336 @Override
337 public final DataSourceProxy getDataSourceProxy()
338 {
339 return dataSourceProxy;
340 }
341
342
343
344
345
346
347
348
349 public String getInsertOrUpdateSqlStatementTemplate()
350 {
351 return insertOrUpdateSqlStatementTemplate;
352 }
353
354
355
356 @Override
357 public final void createConfigTable() throws DataSourceException
358 {
359 try
360 {
361 initDataSource();
362 }
363 catch (final SQLException e)
364 {
365 throw new DataSourceException(new DataSourceMessageBean(
366 DataSourceCode.CANNOT_CREATE_TABLE, e, getDataSourceId()));
367 }
368 }
369
370 private void initDataSource() throws SQLException
371 {
372 if (createTableSqlStatement != null)
373 {
374 if (dropTable)
375 {
376 dropConfigTable();
377 }
378
379 initTables();
380 }
381 }
382
383 private void initTables() throws SQLException
384 {
385 final Connection connection =
386 dataSourceProxy.getDataSource().getConnection();
387
388 try
389 {
390 if (!initializedTableExists(connection))
391 {
392 initTable(connection);
393
394 initProperties(connection);
395 }
396 }
397 finally
398 {
399 connection.close();
400 }
401 }
402
403 private boolean initializedTableExists(final Connection connection)
404 throws SQLException
405 {
406 final Statement statement = connection.createStatement();
407 try
408 {
409
410 final String querySql = "SELECT COUNT(*) FROM " + getTable();
411 final ResultSet resultSet = statement.executeQuery(querySql);
412 if (resultSet.next())
413 {
414 final int count = resultSet.getInt(1);
415 return count > 0;
416 }
417
418 return false;
419 }
420 catch (final SQLException e)
421 {
422 return false;
423 }
424 finally
425 {
426 statement.close();
427 }
428 }
429
430 private void initTable(final Connection connection) throws SQLException
431 {
432 try
433 {
434 execute(connection, createTableSqlStatement);
435 }
436 catch (final SQLException e)
437 {
438 if (!ignoreTableCreationProblems)
439 {
440 throw e;
441 }
442 }
443 }
444
445 private void initProperties(final Connection connection) throws SQLException
446 {
447 if (initialProperties != null && !initialProperties.isEmpty())
448 {
449 final String sql = "INSERT INTO " + getTable() + " VALUES (?, ?, ?)";
450 final PreparedStatement statement = connection.prepareStatement(sql);
451 for (final Entry<String, Map<String, String>> configEntry : initialProperties
452 .entrySet())
453 {
454 final String configName = configEntry.getKey();
455 final Map<String, String> config = configEntry.getValue();
456
457 for (final Entry<String, String> property : config.entrySet())
458 {
459 statement.setString(1, configName);
460 statement.setString(2, property.getKey());
461 statement.setString(3, property.getValue());
462 statement.execute();
463 }
464 }
465
466 statement.close();
467 }
468 }
469
470 private void execute(final Connection connection, final String createTableSql)
471 throws SQLException
472 {
473 final Statement statement = connection.createStatement();
474 try
475 {
476 statement.executeUpdate(createTableSql);
477 }
478 finally
479 {
480 statement.close();
481 }
482 }
483
484 @Override
485 public final void dropConfigTable() throws DataSourceException
486 {
487 try
488 {
489 final Connection connection =
490 dataSourceProxy.getDataSource().getConnection();
491
492 try
493 {
494 final Statement statement = connection.createStatement();
495
496 final String sql = "DROP TABLE " + getTable();
497 statement.executeUpdate(sql);
498 }
499 catch (final SQLException e)
500 {
501 LOG.warn("Dropping failed: " + e.getMessage());
502 }
503 finally
504 {
505 connection.close();
506 }
507 }
508 catch (final SQLException e)
509 {
510 throw new DataSourceException(new DataSourceMessageBean(
511 DataSourceCode.CANNOT_DROP_TABLE, e, getDataSourceId()));
512 }
513 }
514
515 @Override
516 public final void print(final PrintStream out) throws DataSourceException
517 {
518 try
519 {
520 final Connection connection =
521 dataSourceProxy.getDataSource().getConnection();
522
523 try
524 {
525 final Statement statement = connection.createStatement();
526
527 final String querySql =
528 "SELECT " + getConfigColumn() + ", " + getNameColumn() + ", "
529 + getValueColumn() + " FROM " + getTable();
530 final ResultSet resultSet = statement.executeQuery(querySql);
531 while (resultSet.next())
532 {
533 final String config = resultSet.getString(1);
534 final String name = resultSet.getString(2);
535 final String value = resultSet.getString(3);
536
537 out.println(" " + config + " | " + name + "=" + value);
538 }
539 }
540 finally
541 {
542 connection.close();
543 }
544 }
545 catch (final SQLException e)
546 {
547 throw new DataSourceException(new DataSourceMessageBean(
548 DataSourceCode.CANNOT_PRINT_TABLE, e, getDataSourceId()));
549 }
550 }
551
552 @Override
553 public final List<String> getConfigurationKeys() throws DataSourceException
554 {
555 try
556 {
557 final Connection connection =
558 dataSourceProxy.getDataSource().getConnection();
559 final List<String> keys = new ArrayList<String>(32);
560
561 try
562 {
563 final Statement statement = connection.createStatement();
564
565 final String sqlKey = getConfigColumn();
566 final String querySql =
567 "SELECT DISTINCT " + sqlKey + " FROM " + getTable();
568 final ResultSet resultSet = statement.executeQuery(querySql);
569 while (resultSet.next())
570 {
571 final String key = resultSet.getString(sqlKey);
572 keys.add(key);
573 }
574 }
575 finally
576 {
577 connection.close();
578 }
579
580 return keys;
581 }
582 catch (final SQLException e)
583 {
584 throw new DataSourceException(
585 new DataSourceMessageBean(
586 DataSourceCode.CANNOT_ACCESS_CONFIGURATION_KEYS, e,
587 getDataSourceId()));
588 }
589 }
590
591
592
593
594
595
596
597
598 @Override
599 public String toString()
600 {
601 final StringBuilder buffer = new StringBuilder();
602
603 buffer.append(dataSourceProxy);
604
605 return buffer.toString();
606 }
607 }