1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.prometheus.database;
18
19 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogManager;
21 import io.github.tonywasher.joceanus.oceanus.logger.OceanusLogger;
22 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
23 import io.github.tonywasher.joceanus.prometheus.data.PrometheusCryptographyDataType;
24 import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
25 import io.github.tonywasher.joceanus.prometheus.exc.PrometheusIOException;
26 import io.github.tonywasher.joceanus.tethys.api.thread.TethysUIThreadStatusReport;
27
28 import java.sql.Connection;
29 import java.sql.DriverManager;
30 import java.sql.PreparedStatement;
31 import java.sql.SQLException;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.ListIterator;
35 import java.util.Properties;
36
37
38
39
40 public abstract class PrometheusDataStore
41 implements PrometheusDatabaseControl {
42
43
44
45 private static final int NUM_STEPS_PER_TABLE = 3;
46
47
48
49
50 private static final String PROPERTY_USER = "user";
51
52
53
54
55 private static final String PROPERTY_PASS = "password";
56
57
58
59
60 private static final String PROPERTY_INSTANCE = "instance";
61
62
63
64
65 private static final String PROPERTY_ENCRYPT = "encrypt";
66
67
68
69
70 private static final OceanusLogger LOGGER = OceanusLogManager.getLogger(PrometheusDataStore.class);
71
72
73
74
75 private Connection theConn;
76
77
78
79
80 private String theDatabase;
81
82
83
84
85 private final Integer theBatchSize;
86
87
88
89
90 private final PrometheusJDBCDriver theDriver;
91
92
93
94
95 private final List<PrometheusTableInstance<?>> theTables;
96
97
98
99
100
101
102
103
104 protected PrometheusDataStore(final String pDatabase,
105 final PrometheusDBConfig pConfig) throws OceanusException {
106
107 try {
108
109 theBatchSize = pConfig.getBatchSize();
110
111
112 theDriver = pConfig.getDriver();
113
114
115 theDatabase = pDatabase;
116
117
118 final String myConnString = theDriver.getConnectionString(pDatabase, pConfig.getServer(), pConfig.getPort());
119
120
121 final Properties myProperties = new Properties();
122 final String myUser = pConfig.getUser();
123 final char[] myPass = pConfig.getPassword();
124 myProperties.setProperty(PROPERTY_USER, myUser);
125 myProperties.setProperty(PROPERTY_PASS, new String(myPass));
126
127
128 if (theDriver.useInstance()) {
129 final String myInstance = pConfig.getInstance();
130 myProperties.setProperty(PROPERTY_INSTANCE, myInstance);
131 myProperties.setProperty(PROPERTY_ENCRYPT, "false");
132 }
133
134
135 theConn = DriverManager.getConnection(myConnString, myProperties);
136
137
138 theConn.setCatalog(pDatabase);
139
140
141 theConn.setAutoCommit(false);
142
143
144 } catch (SQLException e) {
145 throw new PrometheusIOException("Failed to load driver", e);
146 }
147
148
149 theTables = new ArrayList<>();
150
151
152 for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
153
154 theTables.add(newTable(myType));
155 }
156 }
157
158
159
160
161
162
163
164 protected PrometheusDataStore(final PrometheusDBConfig pConfig) throws OceanusException {
165
166 try {
167
168 theBatchSize = pConfig.getBatchSize();
169
170
171 theDriver = pConfig.getDriver();
172
173
174 final String myConnString = theDriver.getConnectionString(pConfig.getServer(), pConfig.getPort());
175
176
177 final Properties myProperties = new Properties();
178 final String myUser = pConfig.getUser();
179 final char[] myPass = pConfig.getPassword();
180 myProperties.setProperty(PROPERTY_USER, myUser);
181 myProperties.setProperty(PROPERTY_PASS, new String(myPass));
182
183
184 if (theDriver.useInstance()) {
185 final String myInstance = pConfig.getInstance();
186 myProperties.setProperty(PROPERTY_INSTANCE, myInstance);
187 myProperties.setProperty(PROPERTY_ENCRYPT, "false");
188 }
189
190
191 theConn = DriverManager.getConnection(myConnString, myProperties);
192
193
194 theConn.setAutoCommit(false);
195
196
197 } catch (SQLException e) {
198 throw new PrometheusIOException("Failed to load driver", e);
199 }
200
201
202 theTables = new ArrayList<>();
203
204
205 for (PrometheusCryptographyDataType myType : PrometheusCryptographyDataType.values()) {
206
207 theTables.add(newTable(myType));
208 }
209 }
210
211
212
213
214
215
216 public String getName() {
217 return theDatabase;
218 }
219
220
221
222
223
224
225
226 void executeStatement(final String pStatement) throws OceanusException {
227
228 try (PreparedStatement myStmt = theConn.prepareStatement(pStatement)) {
229 theConn.setAutoCommit(true);
230 myStmt.execute();
231 theConn.setAutoCommit(false);
232
233 } catch (SQLException e) {
234 throw new PrometheusIOException("Failed to execute statement", e);
235 }
236 }
237
238
239
240
241
242
243
244 private PrometheusTableDataItem<?> newTable(final PrometheusCryptographyDataType pListType) {
245
246 return switch (pListType) {
247 case CONTROLDATA -> new PrometheusTableControlData(this);
248 case CONTROLKEY -> new PrometheusTableControlKeys(this);
249 case CONTROLKEYSET -> new PrometheusTableControlKeySet(this);
250 case DATAKEYSET -> new PrometheusTableDataKeySet(this);
251 default -> throw new IllegalArgumentException(pListType.toString());
252 };
253 }
254
255 @Override
256 public PrometheusJDBCDriver getDriver() {
257 return theDriver;
258 }
259
260 @Override
261 public Connection getConn() {
262 return theConn;
263 }
264
265
266
267
268
269
270 protected void addTable(final PrometheusTableInstance<?> pTable) {
271 pTable.resolveReferences(theTables);
272 theTables.add(pTable);
273 }
274
275
276
277
278 public void close() {
279
280 if (theConn == null) {
281 return;
282 }
283
284
285 try {
286
287 if (!theConn.getAutoCommit()) {
288 theConn.rollback();
289 }
290
291
292 for (PrometheusTableInstance<?> myInstance : theTables) {
293 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myInstance;
294
295
296 myTable.closeStmt();
297 }
298
299
300 theConn.close();
301 theConn = null;
302
303
304 } catch (SQLException e) {
305 LOGGER.error("Failed to close database connection", e);
306 theConn = null;
307 }
308 }
309
310
311
312
313
314
315
316
317 public void loadDatabase(final TethysUIThreadStatusReport pReport,
318 final PrometheusDataSet pData) throws OceanusException {
319
320 pReport.initTask("loadDatabase");
321 pReport.setNumStages(theTables.size());
322
323
324 OceanusProfile myTask = pReport.getActiveTask();
325 myTask = myTask.startTask("loadDatabase");
326
327
328 for (PrometheusTableInstance<?> myInstance : theTables) {
329 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myInstance;
330
331
332 myTask.startTask(myTable.getTableName());
333
334
335 myTable.loadItems(pReport, pData);
336 }
337
338
339 myTask.end();
340 }
341
342
343
344
345
346
347
348
349 public void updateDatabase(final TethysUIThreadStatusReport pReport,
350 final PrometheusDataSet pData) throws OceanusException {
351
352 final PrometheusBatchControl myBatch = new PrometheusBatchControl(theBatchSize);
353 pReport.setNumStages(NUM_STEPS_PER_TABLE * theTables.size());
354
355
356 OceanusProfile myTask = pReport.getActiveTask();
357 myTask = myTask.startTask("updateDatabase");
358
359
360 OceanusProfile myStage = myTask.startTask("insertData");
361 for (PrometheusTableInstance<?> myInstance : theTables) {
362 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myInstance;
363
364
365 myStage.startTask(myTable.getTableName());
366
367
368 myTable.insertItems(pReport, pData, myBatch);
369 }
370
371
372 myStage = myTask.startTask("updateData");
373 final ListIterator<PrometheusTableInstance<?>> myListIterator = theTables.listIterator();
374 while (myListIterator.hasNext()) {
375 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myListIterator.next();
376
377
378 myStage.startTask(myTable.getTableName());
379
380
381 myTable.updateItems(pReport, myBatch);
382 }
383
384
385 myStage = myTask.startTask("deleteData");
386 while (myListIterator.hasPrevious()) {
387 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myListIterator.previous();
388
389
390 myStage.startTask(myTable.getTableName());
391
392
393 myTable.deleteItems(pReport, myBatch);
394 }
395
396
397 if (myBatch.isActive()) {
398
399 try {
400 theConn.commit();
401 } catch (SQLException e) {
402 close();
403 throw new PrometheusIOException("Failed to commit transaction", e);
404 }
405
406
407 myBatch.commitItems();
408 }
409
410
411 myTask.end();
412 }
413
414
415
416
417
418
419
420
421 public void createDatabase(final TethysUIThreadStatusReport pReport,
422 final String pDatabase) throws OceanusException {
423
424 pReport.setNumStages(2);
425
426
427 OceanusProfile myTask = pReport.getActiveTask();
428 myTask = myTask.startTask("dropDatabase");
429 executeStatement("DROP DATABASE IF EXISTS " + pDatabase);
430
431
432 myTask = myTask.startTask("createDatabase");
433 executeStatement("CREATE DATABASE " + pDatabase);
434
435
436 myTask.end();
437 }
438
439
440
441
442
443
444
445 public void createTables(final TethysUIThreadStatusReport pReport) throws OceanusException {
446
447 pReport.setNumStages(2);
448
449
450 dropTables(pReport);
451
452
453 OceanusProfile myTask = pReport.getActiveTask();
454 myTask = myTask.startTask("createTables");
455
456
457 for (PrometheusTableInstance<?> myInstance : theTables) {
458 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myInstance;
459
460 pReport.checkForCancellation();
461
462
463 myTask.startTask(myTable.getTableName());
464
465
466 myTable.createTable();
467 }
468
469
470 myTask.end();
471 }
472
473
474
475
476
477
478
479 private void dropTables(final TethysUIThreadStatusReport pReport) throws OceanusException {
480
481 OceanusProfile myTask = pReport.getActiveTask();
482 myTask = myTask.startTask("dropTables");
483
484
485 final ListIterator<PrometheusTableInstance<?>> myIterator = theTables.listIterator(theTables.size());
486 while (myIterator.hasPrevious()) {
487 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myIterator.previous();
488
489
490 pReport.checkForCancellation();
491
492
493 myTask.startTask(myTable.getTableName());
494
495
496 myTable.dropTable();
497 }
498
499
500 myTask.end();
501 }
502
503
504
505
506
507
508
509 public void purgeTables(final TethysUIThreadStatusReport pReport) throws OceanusException {
510
511 pReport.setNumStages(1);
512
513
514 OceanusProfile myTask = pReport.getActiveTask();
515 myTask = myTask.startTask("purgeTables");
516
517
518 final ListIterator<PrometheusTableInstance<?>> myIterator = theTables.listIterator(theTables.size());
519 while (myIterator.hasPrevious()) {
520 final PrometheusTableDataItem<?> myTable = (PrometheusTableDataItem<?>) myIterator.previous();
521
522
523 pReport.checkForCancellation();
524
525
526 myTask.startTask(myTable.getTableName());
527
528
529 myTable.purgeTable();
530 }
531
532
533 myTask.end();
534 }
535 }