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