parallel connection testing: avoid deadlocks – preload drivers + better exception handling and logging
--- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sun May 17 15:43:20 2015 +0200
+++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Mon May 18 00:33:10 2015 +0200
@@ -35,6 +35,7 @@
import java.io.PrintStream;
import java.sql.Array;
import java.sql.Driver;
+import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -47,6 +48,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
+import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.sql.rowset.RowSetMetaDataImpl;
@@ -306,6 +308,10 @@
printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
for (final String dbName : options.getDatabaseNamesToTest()) {
+ preloadDriver(dbName);
+ }
+
+ for (final String dbName : options.getDatabaseNamesToTest()) {
es.submit(new Runnable() {
// TODO: Java 8 – lambda
@Override
@@ -335,6 +341,29 @@
printFooter(currentFormatter);
}
+ /**
+ * JDBC driver classes should be preloaded in single thread to avoid deadlocks while doing
+ * {@linkplain DriverManager#registerDriver(java.sql.Driver)} during parallel connections.
+ *
+ * @param dbName
+ */
+ private void preloadDriver(String dbName) {
+ try {
+ DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
+ Driver driver = findDriver(dd);
+ if (driver == null) {
+ log.log(Level.WARNING, "No Driver found for DB: {0}", dbName);
+ } else {
+ log.log(Level.FINEST, "Driver preloading for DB: {0} was successfull", dbName);
+ }
+ } catch (Exception e) {
+ LogRecord r = new LogRecord(Level.WARNING, "Failed to preload the Driver for DB: {0}");
+ r.setParameters(new Object[]{dbName});
+ r.setThrown(e);
+ log.log(r);
+ }
+ }
+
public Object[] testConnection(String dbName) {
log.log(Level.FINE, "Testing connection to database: {0}", dbName);
@@ -349,7 +378,7 @@
succesfullyConnected = dc.test();
}
log.log(Level.FINE, "Database connection test was successful");
- } catch (ConfigurationException | SQLException e) {
+ } catch (ConfigurationException | SQLException | RuntimeException e) {
log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
}
--- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Sun May 17 15:43:20 2015 +0200
+++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Mon May 18 00:33:10 2015 +0200
@@ -78,7 +78,13 @@
try {
Class<Driver> driverClass = (Class<Driver>) Class.forName(driverClassName);
Driver driver = driverClass.newInstance();
- return driver.connect(url, javaProperties);
+ Connection connection = driver.connect(url, javaProperties);
+ if (connection == null) {
+ log.log(Level.SEVERE, "Driver „{0}“ returend null → it does not accept the URL: „{1}“", new Object[]{driverClassName, url});
+ throw new SQLException("Unable to connect: driver returned null.");
+ } else {
+ return connection;
+ }
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException e) {
throw new SQLException("Unable to connect usig specific driver: " + driverClassName, e);
}