1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.smartlab.config;
24
25 import java.io.PrintWriter;
26 import java.sql.CallableStatement;
27 import java.sql.Connection;
28 import java.sql.DatabaseMetaData;
29 import java.sql.PreparedStatement;
30 import java.sql.ResultSet;
31 import java.sql.SQLException;
32 import java.sql.SQLWarning;
33 import java.sql.Savepoint;
34 import java.sql.Statement;
35 import java.util.Map;
36
37 import javax.sql.DataSource;
38
39
40
41
42
43
44 public final class SQLConfiguration extends Configuration {
45
46
47
48
49 private DataSource pool;
50
51
52
53
54
55 private long updated;
56
57
58
59
60 protected final static String LAST_UPDATE = "'smartconfig.last_update'";
61
62
63
64
65
66
67
68
69
70
71
72
73 public SQLConfiguration(Connection connection) throws ConfigurationException {
74 this(new SimpleDataSource(connection));
75 }
76
77
78
79
80
81
82
83 public SQLConfiguration(DataSource pool) throws ConfigurationException {
84 this.pool = pool;
85 this.update();
86 }
87
88
89
90
91 public boolean isChanged() throws ConfigurationException {
92 return this.getLastUpdate(false) > this.updated;
93 }
94
95
96
97
98 public void update() throws ConfigurationException {
99 Connection connection = null;
100 try {
101 connection = pool.getConnection();
102 PreparedStatement statement = connection.prepareStatement("SELECT name, value FROM config WHERE name <> "
103 + LAST_UPDATE);
104 ResultSet rows = statement.executeQuery();
105 while (rows.next()) {
106 String name = rows.getString(1);
107 String value = rows.getString(2);
108 this.add(name, value);
109 }
110 this.updated = this.getLastUpdate(true);
111 } catch (SQLException sqle) {
112 throw new ConfigurationException(sqle);
113 } finally {
114 try {
115 connection.close();
116 } catch (SQLException sqle) {
117 sqle.printStackTrace();
118 } catch (NullPointerException npe) {
119 System.out.println("Unable to retrieve connection");
120 }
121 }
122 }
123
124
125
126
127
128
129
130
131
132
133
134 public long getLastUpdate(boolean set) throws ConfigurationException {
135 Connection connection = null;
136 try {
137 connection = pool.getConnection();
138 PreparedStatement statement = connection.prepareStatement("SELECT value FROM config WHERE name = "
139 + LAST_UPDATE);
140 ResultSet rows = statement.executeQuery();
141 if (rows.next()) {
142 return Long.parseLong(rows.getString(1));
143 } else if (set) {
144 long time = System.currentTimeMillis();
145 this.setLastUpdate(time);
146 return time;
147 } else {
148 throw new ConfigurationException("Cannot find special configuration parameter " + LAST_UPDATE);
149 }
150 } catch (SQLException sqle) {
151 throw new ConfigurationException(sqle);
152 } finally {
153 try {
154 connection.close();
155 } catch (SQLException sqle) {
156 sqle.printStackTrace();
157 } catch (NullPointerException npe) {
158 System.out.println("Unable to retrieve connection");
159 }
160 }
161 }
162
163
164
165
166
167
168
169
170 public void setLastUpdate(long timestamp) throws ConfigurationException {
171 Connection connection = null;
172 try {
173 connection = pool.getConnection();
174 try {
175 connection.prepareStatement("UPDATE config SET value='" + timestamp + "' WHERE name=" + LAST_UPDATE)
176 .execute();
177 } catch (SQLException sqle) {
178 connection.prepareStatement("INSERT INTO config VALUES (" + LAST_UPDATE + ",'" + timestamp + "')")
179 .execute();
180 }
181 } catch (SQLException sqle) {
182 throw new ConfigurationException(sqle);
183 } finally {
184 try {
185 connection.close();
186 } catch (SQLException sqle) {
187 sqle.printStackTrace();
188 } catch (NullPointerException npe) {
189 System.out.println("Unable to retrieve connection");
190 }
191 }
192 }
193
194
195
196
197
198
199
200
201
202 private Element add(String fqn, String value) throws ConfigurationException {
203 String path = null;
204 String name = fqn;
205 int index = -1;
206 String attribute = null;
207 int pathLength = fqn.lastIndexOf(".");
208 int itemSeparator = fqn.indexOf("#");
209 int attributeStart = fqn.indexOf("[");
210 if (pathLength > -1) {
211 path = fqn.substring(0, pathLength);
212 name = fqn.substring(pathLength + 1);
213 }
214 if (itemSeparator > -1) {
215 if (attributeStart > -1) {
216 name = fqn.substring(pathLength + 1, itemSeparator);
217 index = Integer.parseInt(fqn.substring(itemSeparator + 1, attributeStart));
218 attribute = fqn.substring(attributeStart + 1, fqn.length() - 1);
219 } else {
220 name = fqn.substring(pathLength + 1, itemSeparator);
221 index = Integer.parseInt(fqn.substring(itemSeparator + 1));
222 }
223 } else if (attributeStart > -1) {
224 name = fqn.substring(pathLength + 1, attributeStart);
225 attribute = fqn.substring(attributeStart + 1, fqn.length() - 1);
226 }
227 Node parent = null;
228 Element node = null;
229 if (path != null) {
230 parent = this.findNode(this, path);
231 if (parent == null) {
232 parent = (Node)this.add(path, null);
233 }
234 if (index > -1) {
235 try {
236 node = (Element)parent.getElements(name).toArray()[index - 1];
237 } catch (Exception e) {
238 node = null;
239 }
240 } else {
241 node = (Element)parent.getElement(name);
242 }
243 } else if (this.name == null || this.name.equals(name)) {
244 node = this;
245 node.name = name;
246 } else {
247 throw new ConfigurationException("Configuration tree can have only one root node: found " + name
248 + " conflicting with " + this.name);
249 }
250 if (node == null) {
251 if (attribute != null && attribute.equals(Reference.REFERENCE)) {
252 node = new Reference(parent, name, value);
253 } else {
254 node = new Node(parent, name, null);
255 }
256 if (index > -1) {
257 try {
258 parent.children.set(index - 1, node);
259 } catch (IndexOutOfBoundsException ioobe) {
260 parent.children.add(index - 1, node);
261 }
262 } else {
263 parent.children.add(node);
264 }
265 }
266 if (!(node instanceof Reference)) {
267 if (attribute == null) {
268 if (value != null && value.trim().length() > 0) {
269 ((Node)node).setContent(value);
270 }
271 } else {
272 ((Node)node).attributes.put(attribute, value);
273 }
274 }
275 return node;
276 }
277
278
279
280
281
282
283
284
285
286 private Node findNode(Node node, String path) throws ConfigurationException {
287 if (node instanceof SQLConfiguration && path.startsWith(node.name + '.')) {
288 path = path.substring(path.indexOf('.') + 1);
289 }
290 if (node == null || path.equals(node.name)) {
291 return node;
292 }
293 int index = path.indexOf('.');
294 if (index > -1) {
295 String child = path.substring(0, index);
296 return this.findNode((Node)node.getElement(child), path.substring(index + 1));
297 } else {
298 return (Node)node.getElement(path);
299 }
300 }
301
302
303
304
305
306
307
308
309 private static class SimpleDataSource implements DataSource {
310
311
312
313
314 private Connection connection;
315
316
317 public SimpleDataSource(Connection connection) {
318 this.connection = new ConnectionWrapper(connection);
319 }
320
321
322
323
324
325
326
327
328 public Connection getConnection() throws SQLException {
329 return connection;
330 }
331
332 public Connection getConnection(String username, String password) throws SQLException {
333 throw new UnsupportedOperationException();
334 }
335
336 public PrintWriter getLogWriter() throws SQLException {
337 throw new UnsupportedOperationException();
338 }
339
340 public int getLoginTimeout() throws SQLException {
341 throw new UnsupportedOperationException();
342 }
343
344 public void setLogWriter(PrintWriter out) throws SQLException {
345 throw new UnsupportedOperationException();
346 }
347
348 public void setLoginTimeout(int seconds) throws SQLException {
349 throw new UnsupportedOperationException();
350 }
351
352
353
354
355
356
357
358 private static class ConnectionWrapper implements Connection {
359
360 private Connection connection;
361
362
363 public ConnectionWrapper(Connection connection) {
364 this.connection = connection;
365 }
366
367
368
369
370 public void clearWarnings() throws SQLException {
371 connection.clearWarnings();
372 }
373
374
375
376
377 public void close() throws SQLException {
378
379 }
380
381
382
383
384 public void commit() throws SQLException {
385 connection.commit();
386 }
387
388
389
390
391 public Statement createStatement() throws SQLException {
392 return connection.createStatement();
393 }
394
395
396
397
398 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
399 return connection.createStatement(resultSetType, resultSetConcurrency);
400 }
401
402
403
404
405 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
406 throws SQLException {
407 return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
408 }
409
410
411
412
413 public boolean getAutoCommit() throws SQLException {
414 return connection.getAutoCommit();
415 }
416
417
418
419
420 public String getCatalog() throws SQLException {
421 return connection.getCatalog();
422 }
423
424
425
426
427 public int getHoldability() throws SQLException {
428 return connection.getHoldability();
429 }
430
431
432
433
434 public DatabaseMetaData getMetaData() throws SQLException {
435 return connection.getMetaData();
436 }
437
438
439
440
441 public int getTransactionIsolation() throws SQLException {
442 return connection.getTransactionIsolation();
443 }
444
445
446
447
448 public Map getTypeMap() throws SQLException {
449 return connection.getTypeMap();
450 }
451
452
453
454
455 public SQLWarning getWarnings() throws SQLException {
456 return connection.getWarnings();
457 }
458
459
460
461
462 public boolean isClosed() throws SQLException {
463 return connection.isClosed();
464 }
465
466
467
468
469 public boolean isReadOnly() throws SQLException {
470 return connection.isReadOnly();
471 }
472
473
474
475
476 public String nativeSQL(String sql) throws SQLException {
477 return connection.nativeSQL(sql);
478 }
479
480
481
482
483 public CallableStatement prepareCall(String sql) throws SQLException {
484 return connection.prepareCall(sql);
485 }
486
487
488
489
490 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
491 throws SQLException {
492 return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
493 }
494
495
496
497
498
499 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
500 int resultSetHoldability) throws SQLException {
501 return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
502 }
503
504
505
506
507 public PreparedStatement prepareStatement(String sql) throws SQLException {
508 return connection.prepareStatement(sql);
509 }
510
511
512
513
514 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
515 return connection.prepareStatement(sql, autoGeneratedKeys);
516 }
517
518
519
520
521
522 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
523 return connection.prepareStatement(sql, columnIndexes);
524 }
525
526
527
528
529
530 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
531 return connection.prepareStatement(sql, columnNames);
532 }
533
534
535
536
537
538 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
539 throws SQLException {
540 return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
541 }
542
543
544
545
546
547 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
548 int resultSetHoldability) throws SQLException {
549 return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
550 }
551
552
553
554
555 public void releaseSavepoint(Savepoint savepoint) throws SQLException {
556 connection.releaseSavepoint(savepoint);
557 }
558
559
560
561
562 public void rollback() throws SQLException {
563 connection.rollback();
564 }
565
566
567
568
569 public void rollback(Savepoint savepoint) throws SQLException {
570 connection.rollback(savepoint);
571 }
572
573
574
575
576 public void setAutoCommit(boolean autoCommit) throws SQLException {
577 connection.setAutoCommit(autoCommit);
578 }
579
580
581
582
583 public void setCatalog(String catalog) throws SQLException {
584 connection.setCatalog(catalog);
585 }
586
587
588
589
590 public void setHoldability(int holdability) throws SQLException {
591 connection.setHoldability(holdability);
592 }
593
594
595
596
597 public void setReadOnly(boolean readOnly) throws SQLException {
598 connection.setReadOnly(readOnly);
599 }
600
601
602
603
604 public Savepoint setSavepoint() throws SQLException {
605 return connection.setSavepoint();
606 }
607
608
609
610
611 public Savepoint setSavepoint(String name) throws SQLException {
612 return connection.setSavepoint(name);
613 }
614
615
616
617
618 public void setTransactionIsolation(int level) throws SQLException {
619 connection.setTransactionIsolation(level);
620 }
621
622
623
624
625 public void setTypeMap(Map typeMap) throws SQLException {
626 connection.setTypeMap(typeMap);
627 }
628 }
629 }
630 }