parallel connection testing: avoid deadlocks – preload drivers + better exception handling and logging
1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sun May 17 15:43:20 2015 +0200
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Mon May 18 00:33:10 2015 +0200
1.3 @@ -35,6 +35,7 @@
1.4 import java.io.PrintStream;
1.5 import java.sql.Array;
1.6 import java.sql.Driver;
1.7 +import java.sql.DriverManager;
1.8 import java.sql.DriverPropertyInfo;
1.9 import java.sql.SQLException;
1.10 import java.util.ArrayList;
1.11 @@ -47,6 +48,7 @@
1.12 import java.util.concurrent.Executors;
1.13 import java.util.concurrent.TimeUnit;
1.14 import java.util.logging.Level;
1.15 +import java.util.logging.LogRecord;
1.16 import java.util.logging.Logger;
1.17 import javax.sql.rowset.RowSetMetaDataImpl;
1.18
1.19 @@ -306,6 +308,10 @@
1.20 printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
1.21
1.22 for (final String dbName : options.getDatabaseNamesToTest()) {
1.23 + preloadDriver(dbName);
1.24 + }
1.25 +
1.26 + for (final String dbName : options.getDatabaseNamesToTest()) {
1.27 es.submit(new Runnable() {
1.28 // TODO: Java 8 – lambda
1.29 @Override
1.30 @@ -335,6 +341,29 @@
1.31 printFooter(currentFormatter);
1.32 }
1.33
1.34 + /**
1.35 + * JDBC driver classes should be preloaded in single thread to avoid deadlocks while doing
1.36 + * {@linkplain DriverManager#registerDriver(java.sql.Driver)} during parallel connections.
1.37 + *
1.38 + * @param dbName
1.39 + */
1.40 + private void preloadDriver(String dbName) {
1.41 + try {
1.42 + DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
1.43 + Driver driver = findDriver(dd);
1.44 + if (driver == null) {
1.45 + log.log(Level.WARNING, "No Driver found for DB: {0}", dbName);
1.46 + } else {
1.47 + log.log(Level.FINEST, "Driver preloading for DB: {0} was successfull", dbName);
1.48 + }
1.49 + } catch (Exception e) {
1.50 + LogRecord r = new LogRecord(Level.WARNING, "Failed to preload the Driver for DB: {0}");
1.51 + r.setParameters(new Object[]{dbName});
1.52 + r.setThrown(e);
1.53 + log.log(r);
1.54 + }
1.55 + }
1.56 +
1.57 public Object[] testConnection(String dbName) {
1.58 log.log(Level.FINE, "Testing connection to database: {0}", dbName);
1.59
1.60 @@ -349,7 +378,7 @@
1.61 succesfullyConnected = dc.test();
1.62 }
1.63 log.log(Level.FINE, "Database connection test was successful");
1.64 - } catch (ConfigurationException | SQLException e) {
1.65 + } catch (ConfigurationException | SQLException | RuntimeException e) {
1.66 log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
1.67 }
1.68
2.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Sun May 17 15:43:20 2015 +0200
2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Mon May 18 00:33:10 2015 +0200
2.3 @@ -78,7 +78,13 @@
2.4 try {
2.5 Class<Driver> driverClass = (Class<Driver>) Class.forName(driverClassName);
2.6 Driver driver = driverClass.newInstance();
2.7 - return driver.connect(url, javaProperties);
2.8 + Connection connection = driver.connect(url, javaProperties);
2.9 + if (connection == null) {
2.10 + log.log(Level.SEVERE, "Driver „{0}“ returend null → it does not accept the URL: „{1}“", new Object[]{driverClassName, url});
2.11 + throw new SQLException("Unable to connect: driver returned null.");
2.12 + } else {
2.13 + return connection;
2.14 + }
2.15 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException e) {
2.16 throw new SQLException("Unable to connect usig specific driver: " + driverClassName, e);
2.17 }