1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sat Dec 06 14:12:59 2014 +0100
1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Sat Dec 06 14:38:41 2014 +0100
1.3 @@ -43,6 +43,9 @@
1.4 import java.util.List;
1.5 import java.util.ServiceLoader;
1.6 import java.util.Set;
1.7 +import java.util.concurrent.ExecutorService;
1.8 +import java.util.concurrent.Executors;
1.9 +import java.util.concurrent.TimeUnit;
1.10 import java.util.logging.Level;
1.11 import java.util.logging.Logger;
1.12 import javax.sql.rowset.RowSetMetaDataImpl;
1.13 @@ -59,9 +62,9 @@
1.14 * Fake database name for output formatting
1.15 */
1.16 public static final String CONFIG_DB_NAME = "sqldk_configuration";
1.17 - private PrintStream out;
1.18 - private ConfigurationProvider configurationProvider;
1.19 - private CLIOptions options;
1.20 + private final PrintStream out;
1.21 + private final ConfigurationProvider configurationProvider;
1.22 + private final CLIOptions options;
1.23 private Formatter formatter;
1.24
1.25 public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
1.26 @@ -131,7 +134,7 @@
1.27 data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
1.28 }
1.29
1.30 - printTable(formatter, header, data, "-- configured and built-in output formatters", null);
1.31 + printTable(formatter, header, "-- configured and built-in output formatters", null, data);
1.32 }
1.33
1.34 private boolean isInstantiable(FormatterDefinition fd) {
1.35 @@ -152,7 +155,7 @@
1.36 for (SQLType sqlType : SQLType.values()) {
1.37 data.add(new Object[]{sqlType.name(), sqlType.getCode()});
1.38 }
1.39 - printTable(formatter, header, data, "-- data types", null);
1.40 + printTable(formatter, header, "-- data types", null, data);
1.41 log.log(Level.INFO, "Type names in --types option are case insensitive");
1.42 }
1.43
1.44 @@ -172,7 +175,7 @@
1.45 }
1.46 }
1.47
1.48 - printTable(formatter, header, data, "-- configured databases", null);
1.49 + printTable(formatter, header, "-- configured databases", null, data);
1.50 }
1.51
1.52 public void listJdbcDrivers() throws FormatterException, ConfigurationException {
1.53 @@ -195,7 +198,7 @@
1.54 });
1.55 }
1.56
1.57 - printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null);
1.58 + printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
1.59 }
1.60
1.61 public void listJdbcProperties() throws FormatterException, ConfigurationException {
1.62 @@ -257,7 +260,7 @@
1.63 parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
1.64 parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
1.65
1.66 - printTable(formatter, header, data, "-- configured and configurable JDBC driver properties", parameters);
1.67 + printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
1.68 }
1.69 }
1.70
1.71 @@ -277,18 +280,59 @@
1.72 return null;
1.73 }
1.74
1.75 - public void testConnection() throws FormatterException, ConfigurationException {
1.76 + /**
1.77 + * Parallelism for connection testing – maximum concurrent database connections.
1.78 + */
1.79 + private static final int TESTING_THREAD_COUNT = 64;
1.80 + /**
1.81 + * Time limit for all connection testing threads – particular timeouts per connection will be
1.82 + * much smaller.
1.83 + */
1.84 + private static final long TESTING_AWAIT_LIMIT = 1;
1.85 + private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
1.86 +
1.87 + public void testConnections() throws FormatterException, ConfigurationException {
1.88 ColumnsHeader header = constructHeader(
1.89 new HeaderField("database_name", SQLType.VARCHAR),
1.90 new HeaderField("configured", SQLType.BOOLEAN),
1.91 new HeaderField("connected", SQLType.BOOLEAN));
1.92 - List<Object[]> data = new ArrayList<>();
1.93
1.94 - for (String dbName : options.getDatabaseNamesToTest()) {
1.95 - data.add(testConnection(dbName));
1.96 + log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
1.97 +
1.98 + ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
1.99 +
1.100 + final Formatter currentFormatter = formatter;
1.101 +
1.102 + printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
1.103 +
1.104 + for (final String dbName : options.getDatabaseNamesToTest()) {
1.105 + es.submit(new Runnable() {
1.106 + // TODO: Java 8 – lambda
1.107 + @Override
1.108 + public void run() {
1.109 + final Object[] row = testConnection(dbName);
1.110 + synchronized (currentFormatter) {
1.111 + printRow(currentFormatter, row);
1.112 + }
1.113 + }
1.114 + });
1.115 }
1.116
1.117 - printTable(formatter, header, data, "-- database configuration and connectivity test", null);
1.118 + es.shutdown();
1.119 +
1.120 + try {
1.121 + log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
1.122 + boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
1.123 + if (finished) {
1.124 + log.log(Level.FINEST, "All testing threads finished in time limit.");
1.125 + } else {
1.126 + throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
1.127 + }
1.128 + } catch (InterruptedException e) {
1.129 + throw new FormatterException("Interrupted while waiting for test results", e);
1.130 + }
1.131 +
1.132 + printFooter(currentFormatter);
1.133 }
1.134
1.135 public Object[] testConnection(String dbName) {
1.136 @@ -306,7 +350,7 @@
1.137 }
1.138 log.log(Level.FINE, "Database connection test was successful");
1.139 } catch (ConfigurationException | SQLException e) {
1.140 - log.log(Level.SEVERE, "Error during testing connection", e);
1.141 + log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
1.142 }
1.143
1.144 return new Object[]{dbName, succesfullyConfigured, succesfullyConnected};
1.145 @@ -331,26 +375,36 @@
1.146 out.println(line);
1.147 }
1.148
1.149 - private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data, String sql, List<Parameter> parameters) throws ConfigurationException, FormatterException {
1.150 + private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
1.151 + printHeader(formatter, header, sql, parameters);
1.152 +
1.153 + for (Object[] row : data) {
1.154 + printRow(formatter, row);
1.155 + }
1.156 +
1.157 + printFooter(formatter);
1.158 + }
1.159 +
1.160 + private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
1.161 formatter.writeStartStatement();
1.162 -
1.163 if (sql != null) {
1.164 formatter.writeQuery(sql);
1.165 if (parameters != null) {
1.166 formatter.writeParameters(parameters);
1.167 }
1.168 }
1.169 + formatter.writeStartResultSet(header);
1.170 + }
1.171
1.172 - formatter.writeStartResultSet(header);
1.173 + private void printRow(Formatter formatter, Object[] row) {
1.174 + formatter.writeStartRow();
1.175 + for (Object cell : row) {
1.176 + formatter.writeColumnValue(cell);
1.177 + }
1.178 + formatter.writeEndRow();
1.179 + }
1.180
1.181 - for (Object[] row : data) {
1.182 - formatter.writeStartRow();
1.183 - for (Object cell : row) {
1.184 - formatter.writeColumnValue(cell);
1.185 - }
1.186 - formatter.writeEndRow();
1.187 - }
1.188 -
1.189 + private void printFooter(Formatter formatter) {
1.190 formatter.writeEndResultSet();
1.191 formatter.writeEndStatement();
1.192 }
1.193 @@ -397,59 +451,59 @@
1.194 public enum InfoType {
1.195
1.196 HELP {
1.197 - @Override
1.198 - public void showInfo(InfoLister infoLister) {
1.199 - infoLister.printResource(Constants.HELP_FILE);
1.200 - }
1.201 - },
1.202 + @Override
1.203 + public void showInfo(InfoLister infoLister) {
1.204 + infoLister.printResource(Constants.HELP_FILE);
1.205 + }
1.206 + },
1.207 VERSION {
1.208 - @Override
1.209 - public void showInfo(InfoLister infoLister) {
1.210 - infoLister.printResource(Constants.VERSION_FILE);
1.211 - }
1.212 - },
1.213 + @Override
1.214 + public void showInfo(InfoLister infoLister) {
1.215 + infoLister.printResource(Constants.VERSION_FILE);
1.216 + }
1.217 + },
1.218 LICENSE {
1.219 - @Override
1.220 - public void showInfo(InfoLister infoLister) {
1.221 - infoLister.printResource(Constants.LICENSE_FILE);
1.222 - }
1.223 - },
1.224 + @Override
1.225 + public void showInfo(InfoLister infoLister) {
1.226 + infoLister.printResource(Constants.LICENSE_FILE);
1.227 + }
1.228 + },
1.229 FORMATTERS {
1.230 - @Override
1.231 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.232 - infoLister.listFormatters();
1.233 - }
1.234 - },
1.235 + @Override
1.236 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.237 + infoLister.listFormatters();
1.238 + }
1.239 + },
1.240 TYPES {
1.241 - @Override
1.242 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.243 - infoLister.listTypes();
1.244 - }
1.245 - },
1.246 + @Override
1.247 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.248 + infoLister.listTypes();
1.249 + }
1.250 + },
1.251 JDBC_DRIVERS {
1.252 - @Override
1.253 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.254 - infoLister.listJdbcDrivers();
1.255 - }
1.256 - },
1.257 + @Override
1.258 + public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.259 + infoLister.listJdbcDrivers();
1.260 + }
1.261 + },
1.262 JDBC_PROPERTIES {
1.263 - @Override
1.264 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.265 - infoLister.listJdbcProperties();
1.266 - }
1.267 - },
1.268 + @Override
1.269 + public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.270 + infoLister.listJdbcProperties();
1.271 + }
1.272 + },
1.273 DATABASES {
1.274 - @Override
1.275 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.276 - infoLister.listDatabases();
1.277 - }
1.278 - },
1.279 + @Override
1.280 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.281 + infoLister.listDatabases();
1.282 + }
1.283 + },
1.284 CONNECTION {
1.285 - @Override
1.286 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.287 - infoLister.testConnection();
1.288 - }
1.289 - };
1.290 + @Override
1.291 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.292 + infoLister.testConnections();
1.293 + }
1.294 + };
1.295
1.296 public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
1.297 }