--- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sat Dec 06 14:12:59 2014 +0100
+++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sat Dec 06 14:38:41 2014 +0100
@@ -43,6 +43,9 @@
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.rowset.RowSetMetaDataImpl;
@@ -59,9 +62,9 @@
* Fake database name for output formatting
*/
public static final String CONFIG_DB_NAME = "sqldk_configuration";
- private PrintStream out;
- private ConfigurationProvider configurationProvider;
- private CLIOptions options;
+ private final PrintStream out;
+ private final ConfigurationProvider configurationProvider;
+ private final CLIOptions options;
private Formatter formatter;
public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
@@ -131,7 +134,7 @@
data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
}
- printTable(formatter, header, data, "-- configured and built-in output formatters", null);
+ printTable(formatter, header, "-- configured and built-in output formatters", null, data);
}
private boolean isInstantiable(FormatterDefinition fd) {
@@ -152,7 +155,7 @@
for (SQLType sqlType : SQLType.values()) {
data.add(new Object[]{sqlType.name(), sqlType.getCode()});
}
- printTable(formatter, header, data, "-- data types", null);
+ printTable(formatter, header, "-- data types", null, data);
log.log(Level.INFO, "Type names in --types option are case insensitive");
}
@@ -172,7 +175,7 @@
}
}
- printTable(formatter, header, data, "-- configured databases", null);
+ printTable(formatter, header, "-- configured databases", null, data);
}
public void listJdbcDrivers() throws FormatterException, ConfigurationException {
@@ -195,7 +198,7 @@
});
}
- printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null);
+ printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
}
public void listJdbcProperties() throws FormatterException, ConfigurationException {
@@ -257,7 +260,7 @@
parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
- printTable(formatter, header, data, "-- configured and configurable JDBC driver properties", parameters);
+ printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
}
}
@@ -277,18 +280,59 @@
return null;
}
- public void testConnection() throws FormatterException, ConfigurationException {
+ /**
+ * Parallelism for connection testing – maximum concurrent database connections.
+ */
+ private static final int TESTING_THREAD_COUNT = 64;
+ /**
+ * Time limit for all connection testing threads – particular timeouts per connection will be
+ * much smaller.
+ */
+ private static final long TESTING_AWAIT_LIMIT = 1;
+ private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
+
+ public void testConnections() throws FormatterException, ConfigurationException {
ColumnsHeader header = constructHeader(
new HeaderField("database_name", SQLType.VARCHAR),
new HeaderField("configured", SQLType.BOOLEAN),
new HeaderField("connected", SQLType.BOOLEAN));
- List<Object[]> data = new ArrayList<>();
+
+ log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
+
+ ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
+
+ final Formatter currentFormatter = formatter;
+
+ printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
- for (String dbName : options.getDatabaseNamesToTest()) {
- data.add(testConnection(dbName));
+ for (final String dbName : options.getDatabaseNamesToTest()) {
+ es.submit(new Runnable() {
+ // TODO: Java 8 – lambda
+ @Override
+ public void run() {
+ final Object[] row = testConnection(dbName);
+ synchronized (currentFormatter) {
+ printRow(currentFormatter, row);
+ }
+ }
+ });
}
- printTable(formatter, header, data, "-- database configuration and connectivity test", null);
+ es.shutdown();
+
+ try {
+ log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
+ boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
+ if (finished) {
+ log.log(Level.FINEST, "All testing threads finished in time limit.");
+ } else {
+ throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
+ }
+ } catch (InterruptedException e) {
+ throw new FormatterException("Interrupted while waiting for test results", e);
+ }
+
+ printFooter(currentFormatter);
}
public Object[] testConnection(String dbName) {
@@ -306,7 +350,7 @@
}
log.log(Level.FINE, "Database connection test was successful");
} catch (ConfigurationException | SQLException e) {
- log.log(Level.SEVERE, "Error during testing connection", e);
+ log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
}
return new Object[]{dbName, succesfullyConfigured, succesfullyConnected};
@@ -331,26 +375,36 @@
out.println(line);
}
- private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data, String sql, List<Parameter> parameters) throws ConfigurationException, FormatterException {
+ private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
+ printHeader(formatter, header, sql, parameters);
+
+ for (Object[] row : data) {
+ printRow(formatter, row);
+ }
+
+ printFooter(formatter);
+ }
+
+ private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
formatter.writeStartStatement();
-
if (sql != null) {
formatter.writeQuery(sql);
if (parameters != null) {
formatter.writeParameters(parameters);
}
}
-
formatter.writeStartResultSet(header);
+ }
- for (Object[] row : data) {
- formatter.writeStartRow();
- for (Object cell : row) {
- formatter.writeColumnValue(cell);
- }
- formatter.writeEndRow();
+ private void printRow(Formatter formatter, Object[] row) {
+ formatter.writeStartRow();
+ for (Object cell : row) {
+ formatter.writeColumnValue(cell);
}
+ formatter.writeEndRow();
+ }
+ private void printFooter(Formatter formatter) {
formatter.writeEndResultSet();
formatter.writeEndStatement();
}
@@ -397,59 +451,59 @@
public enum InfoType {
HELP {
- @Override
- public void showInfo(InfoLister infoLister) {
- infoLister.printResource(Constants.HELP_FILE);
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) {
+ infoLister.printResource(Constants.HELP_FILE);
+ }
+ },
VERSION {
- @Override
- public void showInfo(InfoLister infoLister) {
- infoLister.printResource(Constants.VERSION_FILE);
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) {
+ infoLister.printResource(Constants.VERSION_FILE);
+ }
+ },
LICENSE {
- @Override
- public void showInfo(InfoLister infoLister) {
- infoLister.printResource(Constants.LICENSE_FILE);
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) {
+ infoLister.printResource(Constants.LICENSE_FILE);
+ }
+ },
FORMATTERS {
- @Override
- public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
- infoLister.listFormatters();
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
+ infoLister.listFormatters();
+ }
+ },
TYPES {
- @Override
- public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
- infoLister.listTypes();
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
+ infoLister.listTypes();
+ }
+ },
JDBC_DRIVERS {
- @Override
- public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
- infoLister.listJdbcDrivers();
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
+ infoLister.listJdbcDrivers();
+ }
+ },
JDBC_PROPERTIES {
- @Override
- public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
- infoLister.listJdbcProperties();
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
+ infoLister.listJdbcProperties();
+ }
+ },
DATABASES {
- @Override
- public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
- infoLister.listDatabases();
- }
- },
+ @Override
+ public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
+ infoLister.listDatabases();
+ }
+ },
CONNECTION {
- @Override
- public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
- infoLister.testConnection();
- }
- };
+ @Override
+ public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
+ infoLister.testConnections();
+ }
+ };
public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
}