1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package edu.internet2.middleware.grouperInstaller.util;
21
22 import java.io.File;
23 import java.sql.Connection;
24 import java.sql.DriverManager;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Set;
32
33 import edu.internet2.middleware.grouperInstaller.driverShim.HsqlShim;
34 import edu.internet2.middleware.grouperInstaller.driverShim.MySqlShim;
35 import edu.internet2.middleware.grouperInstaller.driverShim.OracleShim;
36 import edu.internet2.middleware.grouperInstaller.driverShim.PostgresShim;
37 import edu.internet2.middleware.grouperInstaller.driverShim.SqlServerShim;
38 import edu.internet2.middleware.grouperInstallerExt.org.apache.commons.logging.Log;
39
40
41
42
43
44 public class GiDbUtils {
45
46
47
48
49 private String url;
50
51
52
53
54 private String user;
55
56
57
58
59 private String pass;
60
61
62
63
64
65
66
67 public GiDbUtils(String url, String user, String pass) {
68 super();
69 this.url = url;
70 this.user = user;
71 this.pass = pass;
72 }
73
74
75
76
77 private static Set<String> driversRegistered = new HashSet<String>();
78
79
80
81
82
83
84 public void registerDriverOnce(String appDir) {
85 String driver = convertUrlToDriverClassIfNeeded(this.url, null);
86 if (driversRegistered.contains(driver)) {
87 return;
88 }
89
90 try {
91 Class.forName(driver);
92
93 } catch (ClassNotFoundException e) {
94
95
96 String prefix = null;
97 if (this.isHsql()) {
98 prefix = "hsql";
99 } else if (this.isMysql()) {
100 prefix = "mysql";
101 } else if (this.isOracle()) {
102 prefix = "ojdbc";
103 } else if (this.isPostgres()) {
104 prefix = "postgres";
105 } else if (this.isSQLServer()) {
106 prefix = "sqljdbc";
107 } else {
108 throw new RuntimeException("What kind of database is this???? " + this.url);
109 }
110
111 List<File> allFiles = GrouperInstallerUtils.fileListRecursive(new File(appDir));
112 File driverJar = null;
113 for (File file : allFiles) {
114 if (file.getName().endsWith(".jar") && file.getName().startsWith(prefix)) {
115
116
117 if (driverJar == null || driverJar.lastModified() < file.lastModified()) {
118 driverJar = file;
119 }
120 }
121 }
122
123 if (driverJar == null) {
124 System.out.println("Cant find driver jar that starts with '" + prefix + "' and ends with .jar!!! in directory: " + appDir);
125 System.exit(1);
126 }
127 try {
128 if (this.isHsql()) {
129 HsqlShim.init(driverJar);
130 HsqlShimperInstaller/driverShim/HsqlShim.html#HsqlShim">HsqlShim hsqlShim = new HsqlShim();
131 DriverManager.registerDriver(hsqlShim);
132 } else if (this.isMysql()) {
133 MySqlShim.init(driverJar);
134 MySqlShimrInstaller/driverShim/MySqlShim.html#MySqlShim">MySqlShim mysqlShim = new MySqlShim();
135 DriverManager.registerDriver(mysqlShim);
136 } else if (this.isOracle()) {
137 OracleShim.init(driverJar);
138 OracleShimnstaller/driverShim/OracleShim.html#OracleShim">OracleShim oracleShim = new OracleShim();
139 DriverManager.registerDriver(oracleShim);
140 } else if (this.isPostgres()) {
141 PostgresShim.init(driverJar);
142 PostgresShimller/driverShim/PostgresShim.html#PostgresShim">PostgresShim postgresShim = new PostgresShim();
143 DriverManager.registerDriver(postgresShim);
144 } else if (this.isSQLServer()) {
145 SqlServerShim.init(driverJar);
146 SqlServerShimer/driverShim/SqlServerShim.html#SqlServerShim">SqlServerShim sqlServerShim = new SqlServerShim();
147 DriverManager.registerDriver(sqlServerShim);
148 } else {
149 throw new RuntimeException("What kind of database is this???? " + this.url);
150 }
151 } catch (SQLException sqle) {
152 throw new RuntimeException("Problem registering driver: " + this.url, sqle);
153 }
154 }
155 driversRegistered.add(driver);
156 }
157
158
159
160
161 public static enum DbType {
162
163
164 STRING {
165
166
167
168
169
170 @Override
171 public Object processResultSet(ResultSet resultSet, int indexZeroIndexed) {
172 try {
173 return resultSet.getString(indexZeroIndexed+1);
174 } catch (SQLException e) {
175 throw new RuntimeException("Error reading col (zero indexed) " + indexZeroIndexed, e);
176 }
177 }
178
179
180
181
182 @Override
183 public void attachParam(PreparedStatement preparedStatement, Object arg,
184 int indexZeroIndexed) {
185 String argString = GrouperInstallerUtils.stringValue(arg);
186 try {
187 preparedStatement.setString(indexZeroIndexed+1, argString);
188 } catch (SQLException e) {
189 throw new RuntimeException("Error setting param (zero indexed) " + indexZeroIndexed + ": " + argString, e);
190 }
191 }
192 };
193
194
195
196
197
198
199
200 public abstract Object processResultSet(ResultSet resultSet, int indexZeroIndexed);
201
202
203
204
205
206
207
208 public abstract void attachParam(PreparedStatement preparedStatement, Object arg, int indexZeroIndexed);
209
210
211
212
213
214
215 public static DbType fromObject(Object object) {
216
217 if (object == null || object instanceof String) {
218 return DbType.STRING;
219 }
220 throw new RuntimeException("Unsupported type: " + GrouperInstallerUtils.className(object) + ", " + object);
221 }
222
223
224
225
226
227
228 public static DbType fromClass(Class<?> theClass) {
229
230 if (theClass instanceof Class<?> && String.class.equals(theClass)) {
231 return DbType.STRING;
232 }
233
234 throw new RuntimeException("Unsupported type: " + theClass);
235 }
236
237 }
238
239
240
241
242
243 public boolean isHsql() {
244 return isHsql(this.url);
245 }
246
247
248
249
250
251
252 public static boolean isHsql(String connectionUrl) {
253 return GrouperInstallerUtils.defaultString(connectionUrl).toLowerCase().contains(":hsqldb:");
254 }
255
256
257
258
259
260 public boolean isPostgres() {
261 return isPostgres(this.url);
262 }
263
264
265
266
267
268
269 public static boolean isPostgres(String connectionUrl) {
270 return GrouperInstallerUtils.defaultString(connectionUrl).toLowerCase().contains(":postgresql:");
271 }
272
273
274
275
276
277 public boolean isOracle() {
278 return isOracle(this.url);
279 }
280
281
282
283
284
285
286 public static boolean isOracle(String connectionUrl) {
287 return GrouperInstallerUtils.defaultString(connectionUrl).toLowerCase().contains(":oracle:");
288 }
289
290
291
292
293
294 public boolean isMysql() {
295 return isMysql(this.url);
296 }
297
298
299
300
301
302
303 public static boolean isMysql(String connectionUrl) {
304 return GrouperInstallerUtils.defaultString(connectionUrl).toLowerCase().contains(":mysql:");
305 }
306
307
308
309
310
311 public boolean isSQLServer() {
312 return isSQLServer(this.url);
313 }
314
315
316
317
318
319
320 public static boolean isSQLServer(String connectionUrl) {
321 return GrouperInstallerUtils.defaultString(connectionUrl).toLowerCase().contains(":sqlserver:");
322 }
323
324
325
326
327
328
329
330
331 public static String convertUrlToDriverClassIfNeeded(String connectionUrl, String driverClassName) {
332
333 if (GrouperInstallerUtils.isBlank(driverClassName)) {
334
335 if (isHsql(connectionUrl)) {
336 driverClassName = "org.hsqldb.jdbcDriver";
337 } else if (isMysql(connectionUrl)) {
338 driverClassName = "com.mysql.jdbc.Driver";
339 } else if (isOracle(connectionUrl)) {
340 driverClassName = "oracle.jdbc.driver.OracleDriver";
341 } else if (isPostgres(connectionUrl)) {
342 driverClassName = "org.postgresql.Driver";
343 } else if (isSQLServer(connectionUrl)) {
344 driverClassName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
345 } else {
346
347
348 if (!GrouperInstallerUtils.isBlank(connectionUrl)) {
349
350 String error = "Cannot determine the driver class from database URL: " + connectionUrl;
351 System.err.println(error);
352 LOG.error(error);
353 return null;
354 }
355 }
356 }
357 return driverClassName;
358
359 }
360
361
362
363
364
365 public Connection connection() {
366
367 String oracleUrl = null;
368
369 try {
370
371
372
373
374
375
376 Connection conn = DriverManager.getConnection(this.url, this.user, this.pass);
377 conn.setAutoCommit(false);
378 return conn;
379 } catch (Exception e) {
380 throw new RuntimeException("Error connecting to: " + oracleUrl, e);
381 }
382 }
383
384
385
386
387
388
389
390
391
392 public <T> List<T> listSelect(Class<T> rowType, String query, List<DbType> returnColTypes) {
393 return listSelect(rowType, query, returnColTypes, null);
394 }
395
396
397
398
399
400
401
402
403 public <T> T select(Class<T> colType, String query) {
404 List<T> rows = listSelect(colType, query, GrouperInstallerUtils.toList(DbType.fromClass(colType)));
405
406 T data = GrouperInstallerUtils.listPopOne(rows);
407
408 return data;
409 }
410
411
412
413
414
415
416
417
418
419
420 @SuppressWarnings("unchecked")
421 public <T> List<T> listSelect(Class<T> rowType, String query, List<DbType> returnColTypes, List<Object> args) {
422 Connection connection = null;
423 PreparedStatement preparedStatement = null;
424 ResultSet resultSet = null;
425 List<T> results = new ArrayList<T>();
426
427 try {
428
429 int returnColTypesLength = GrouperInstallerUtils.length(returnColTypes);
430 if (returnColTypesLength==0) {
431 throw new RuntimeException("Why is returnColTypesLength == 0???");
432 }
433
434 connection = this.connection();
435 preparedStatement = connection.prepareStatement(query);
436
437
438 int argsLength = GrouperInstallerUtils.length(args);
439
440 for (int i=0; i<argsLength;i++) {
441 Object arg = args.get(i);
442 DbType dbType = DbType.fromObject(arg);
443 dbType.attachParam(preparedStatement, arg, i);
444 }
445
446 resultSet = preparedStatement.executeQuery();
447
448 if (rowType.isArray() != returnColTypesLength>1) {
449 throw new RuntimeException("If returnColTypesLength > 1 (" + returnColTypesLength + ") then you must pass in an array as the return type");
450 }
451
452 while (resultSet.next()) {
453
454
455 if (rowType.isArray()) {
456
457 Object[] result = new Object[returnColTypesLength];
458 results.add((T)result);
459
460 for (int i=0; i<returnColTypesLength;i++) {
461 result[i] = returnColTypes.get(i).processResultSet(resultSet, i);
462 }
463 } else {
464
465 results.add((T)returnColTypes.get(0).processResultSet(resultSet, 0));
466 }
467
468 }
469 } catch (Exception e) {
470 throw new RuntimeException("Error with query: " + query, e);
471 }
472 finally {
473 rollbackQuietly(connection);
474 GrouperInstallerUtils.closeQuietly(resultSet);
475 GrouperInstallerUtils.closeQuietly(preparedStatement);
476 GrouperInstallerUtils.closeQuietly(connection);
477 }
478 return results;
479
480 }
481
482
483
484
485
486 public void rollbackQuietly(Connection connection) {
487 try {
488 if (connection != null) {
489 connection.rollback();
490 }
491 } catch (Exception e) {
492 LOG.error("Problem rolling back", e);
493
494 }
495
496 }
497
498
499
500
501
502
503
504
505 public int executeUpdate(String query, Object arg) {
506
507 List<Object> args = GrouperInstallerUtils.toList(arg);
508 return executeUpdate(query, args);
509
510 }
511
512
513
514
515
516
517
518 public int executeUpdate(String query) {
519
520 return executeUpdate(query, null);
521
522 }
523
524
525
526
527
528
529
530
531 public int executeUpdate(String query, List<Object> args) {
532 return executeUpdate(query, args, true);
533 }
534
535
536
537
538
539 public Exception checkConnection() {
540
541 String query = checkConnectionQuery();
542
543 try {
544 select(String.class, query);
545 } catch (Exception e) {
546 return e;
547 }
548 return null;
549 }
550
551
552
553
554
555 public String checkConnectionQuery() {
556 if (this.isHsql()) {
557 return "SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS";
558 }
559 if (this.isMysql()) {
560 return "select 1";
561 }
562 if (this.isOracle()) {
563 return "select 1 from dual";
564 }
565 if (this.isPostgres()) {
566 return "select 1";
567 }
568 if (this.isSQLServer()) {
569 return "select 1";
570 }
571 throw new RuntimeException("Cant find which database type from URL: " + this.url);
572
573 }
574
575
576
577
578
579
580
581
582
583 public int executeUpdate(String query, List<Object> args, boolean commit) {
584 Connection connection = null;
585 PreparedStatement preparedStatement = null;
586
587 try {
588 connection = this.connection();
589 preparedStatement = connection.prepareStatement(query);
590
591
592 int argsLength = GrouperInstallerUtils.length(args);
593
594 for (int i=0; i<argsLength;i++) {
595 Object arg = args.get(i);
596 DbType dbType = DbType.fromObject(arg);
597 dbType.attachParam(preparedStatement, arg, i);
598 }
599
600 int result = preparedStatement.executeUpdate();
601
602 if (commit) {
603 connection.commit();
604 }
605
606 return result;
607
608 } catch (Exception e) {
609 rollbackQuietly(connection);
610 throw new RuntimeException("Error with query: " + query, e);
611 }
612 finally {
613 GrouperInstallerUtils.closeQuietly(preparedStatement);
614 GrouperInstallerUtils.closeQuietly(connection);
615 }
616
617 }
618
619
620
621
622 private static Log LOG = GrouperInstallerUtils.retrieveLog(GiDbUtils.class);
623 }