java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java
branchv_0
changeset 183 1bb5abfb0655
parent 161 385929a50dd9
child 196 76da38d49e81
equal deleted inserted replaced
182:4ff7a273f3e8 183:1bb5abfb0655
    41 import java.util.EnumSet;
    41 import java.util.EnumSet;
    42 import java.util.HashSet;
    42 import java.util.HashSet;
    43 import java.util.List;
    43 import java.util.List;
    44 import java.util.ServiceLoader;
    44 import java.util.ServiceLoader;
    45 import java.util.Set;
    45 import java.util.Set;
       
    46 import java.util.concurrent.ExecutorService;
       
    47 import java.util.concurrent.Executors;
       
    48 import java.util.concurrent.TimeUnit;
    46 import java.util.logging.Level;
    49 import java.util.logging.Level;
    47 import java.util.logging.Logger;
    50 import java.util.logging.Logger;
    48 import javax.sql.rowset.RowSetMetaDataImpl;
    51 import javax.sql.rowset.RowSetMetaDataImpl;
    49 
    52 
    50 /**
    53 /**
    57 	private static final Logger log = Logger.getLogger(InfoLister.class.getName());
    60 	private static final Logger log = Logger.getLogger(InfoLister.class.getName());
    58 	/**
    61 	/**
    59 	 * Fake database name for output formatting
    62 	 * Fake database name for output formatting
    60 	 */
    63 	 */
    61 	public static final String CONFIG_DB_NAME = "sqldk_configuration";
    64 	public static final String CONFIG_DB_NAME = "sqldk_configuration";
    62 	private PrintStream out;
    65 	private final PrintStream out;
    63 	private ConfigurationProvider configurationProvider;
    66 	private final ConfigurationProvider configurationProvider;
    64 	private CLIOptions options;
    67 	private final CLIOptions options;
    65 	private Formatter formatter;
    68 	private Formatter formatter;
    66 
    69 
    67 	public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
    70 	public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
    68 		this.out = out;
    71 		this.out = out;
    69 		this.configurationProvider = configurationProvider;
    72 		this.configurationProvider = configurationProvider;
   129 
   132 
   130 		for (FormatterDefinition fd : configurationProvider.getConfiguration().getFormatters()) {
   133 		for (FormatterDefinition fd : configurationProvider.getConfiguration().getFormatters()) {
   131 			data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
   134 			data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
   132 		}
   135 		}
   133 
   136 
   134 		printTable(formatter, header, data, "-- configured and built-in output formatters", null);
   137 		printTable(formatter, header, "-- configured and built-in output formatters", null, data);
   135 	}
   138 	}
   136 
   139 
   137 	private boolean isInstantiable(FormatterDefinition fd) {
   140 	private boolean isInstantiable(FormatterDefinition fd) {
   138 		try {
   141 		try {
   139 			try (ByteArrayOutputStream testStream = new ByteArrayOutputStream()) {
   142 			try (ByteArrayOutputStream testStream = new ByteArrayOutputStream()) {
   150 		ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("code", SQLType.INTEGER));
   153 		ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("code", SQLType.INTEGER));
   151 		List<Object[]> data = new ArrayList<>();
   154 		List<Object[]> data = new ArrayList<>();
   152 		for (SQLType sqlType : SQLType.values()) {
   155 		for (SQLType sqlType : SQLType.values()) {
   153 			data.add(new Object[]{sqlType.name(), sqlType.getCode()});
   156 			data.add(new Object[]{sqlType.name(), sqlType.getCode()});
   154 		}
   157 		}
   155 		printTable(formatter, header, data, "-- data types", null);
   158 		printTable(formatter, header, "-- data types", null, data);
   156 		log.log(Level.INFO, "Type names in --types option are case insensitive");
   159 		log.log(Level.INFO, "Type names in --types option are case insensitive");
   157 	}
   160 	}
   158 
   161 
   159 	public void listDatabases() throws ConfigurationException, FormatterException {
   162 	public void listDatabases() throws ConfigurationException, FormatterException {
   160 		ColumnsHeader header = constructHeader(
   163 		ColumnsHeader header = constructHeader(
   170 			for (DatabaseDefinition dd : configuredDatabases) {
   173 			for (DatabaseDefinition dd : configuredDatabases) {
   171 				data.add(new Object[]{dd.getName(), dd.getUserName(), dd.getUrl()});
   174 				data.add(new Object[]{dd.getName(), dd.getUserName(), dd.getUrl()});
   172 			}
   175 			}
   173 		}
   176 		}
   174 
   177 
   175 		printTable(formatter, header, data, "-- configured databases", null);
   178 		printTable(formatter, header, "-- configured databases", null, data);
   176 	}
   179 	}
   177 
   180 
   178 	public void listJdbcDrivers() throws FormatterException, ConfigurationException {
   181 	public void listJdbcDrivers() throws FormatterException, ConfigurationException {
   179 		ColumnsHeader header = constructHeader(
   182 		ColumnsHeader header = constructHeader(
   180 				new HeaderField("class", SQLType.VARCHAR),
   183 				new HeaderField("class", SQLType.VARCHAR),
   193 				d.getMinorVersion(),
   196 				d.getMinorVersion(),
   194 				d.jdbcCompliant()
   197 				d.jdbcCompliant()
   195 			});
   198 			});
   196 		}
   199 		}
   197 
   200 
   198 		printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null);
   201 		printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
   199 	}
   202 	}
   200 
   203 
   201 	public void listJdbcProperties() throws FormatterException, ConfigurationException {
   204 	public void listJdbcProperties() throws FormatterException, ConfigurationException {
   202 		for (String dbName : options.getDatabaseNamesToListProperties()) {
   205 		for (String dbName : options.getDatabaseNamesToListProperties()) {
   203 			ColumnsHeader header = constructHeader(
   206 			ColumnsHeader header = constructHeader(
   255 				parameters.add(new NamedParameter("databgase", dbName, SQLType.VARCHAR));
   258 				parameters.add(new NamedParameter("databgase", dbName, SQLType.VARCHAR));
   256 				parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
   259 				parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
   257 				parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
   260 				parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
   258 				parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
   261 				parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
   259 
   262 
   260 				printTable(formatter, header, data, "-- configured and configurable JDBC driver properties", parameters);
   263 				printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
   261 			}
   264 			}
   262 		}
   265 		}
   263 
   266 
   264 	}
   267 	}
   265 
   268 
   275 			}
   278 			}
   276 		}
   279 		}
   277 		return null;
   280 		return null;
   278 	}
   281 	}
   279 
   282 
   280 	public void testConnection() throws FormatterException, ConfigurationException {
   283 	/**
       
   284 	 * Parallelism for connection testing – maximum concurrent database connections.
       
   285 	 */
       
   286 	private static final int TESTING_THREAD_COUNT = 64;
       
   287 	/**
       
   288 	 * Time limit for all connection testing threads – particular timeouts per connection will be
       
   289 	 * much smaller.
       
   290 	 */
       
   291 	private static final long TESTING_AWAIT_LIMIT = 1;
       
   292 	private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
       
   293 
       
   294 	public void testConnections() throws FormatterException, ConfigurationException {
   281 		ColumnsHeader header = constructHeader(
   295 		ColumnsHeader header = constructHeader(
   282 				new HeaderField("database_name", SQLType.VARCHAR),
   296 				new HeaderField("database_name", SQLType.VARCHAR),
   283 				new HeaderField("configured", SQLType.BOOLEAN),
   297 				new HeaderField("configured", SQLType.BOOLEAN),
   284 				new HeaderField("connected", SQLType.BOOLEAN));
   298 				new HeaderField("connected", SQLType.BOOLEAN));
   285 		List<Object[]> data = new ArrayList<>();
   299 
   286 
   300 		log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
   287 		for (String dbName : options.getDatabaseNamesToTest()) {
   301 
   288 			data.add(testConnection(dbName));
   302 		ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
   289 		}
   303 
   290 
   304 		final Formatter currentFormatter = formatter;
   291 		printTable(formatter, header, data, "-- database configuration and connectivity test", null);
   305 
       
   306 		printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
       
   307 
       
   308 		for (final String dbName : options.getDatabaseNamesToTest()) {
       
   309 			es.submit(new Runnable() {
       
   310 				// TODO: Java 8 – lambda
       
   311 				@Override
       
   312 				public void run() {
       
   313 					final Object[] row = testConnection(dbName);
       
   314 					synchronized (currentFormatter) {
       
   315 						printRow(currentFormatter, row);
       
   316 					}
       
   317 				}
       
   318 			});
       
   319 		}
       
   320 
       
   321 		es.shutdown();
       
   322 
       
   323 		try {
       
   324 			log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
       
   325 			boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
       
   326 			if (finished) {
       
   327 				log.log(Level.FINEST, "All testing threads finished in time limit.");
       
   328 			} else {
       
   329 				throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
       
   330 			}
       
   331 		} catch (InterruptedException e) {
       
   332 			throw new FormatterException("Interrupted while waiting for test results", e);
       
   333 		}
       
   334 
       
   335 		printFooter(currentFormatter);
   292 	}
   336 	}
   293 
   337 
   294 	public Object[] testConnection(String dbName) {
   338 	public Object[] testConnection(String dbName) {
   295 		log.log(Level.FINE, "Testing connection to database: {0}", dbName);
   339 		log.log(Level.FINE, "Testing connection to database: {0}", dbName);
   296 
   340 
   304 			try (DatabaseConnection dc = dd.connect(options.getDatabaseProperties())) {
   348 			try (DatabaseConnection dc = dd.connect(options.getDatabaseProperties())) {
   305 				succesfullyConnected = dc.test();
   349 				succesfullyConnected = dc.test();
   306 			}
   350 			}
   307 			log.log(Level.FINE, "Database connection test was successful");
   351 			log.log(Level.FINE, "Database connection test was successful");
   308 		} catch (ConfigurationException | SQLException e) {
   352 		} catch (ConfigurationException | SQLException e) {
   309 			log.log(Level.SEVERE, "Error during testing connection", e);
   353 			log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
   310 		}
   354 		}
   311 
   355 
   312 		return new Object[]{dbName, succesfullyConfigured, succesfullyConnected};
   356 		return new Object[]{dbName, succesfullyConfigured, succesfullyConnected};
   313 	}
   357 	}
   314 
   358 
   329 
   373 
   330 	private void println(String line) {
   374 	private void println(String line) {
   331 		out.println(line);
   375 		out.println(line);
   332 	}
   376 	}
   333 
   377 
   334 	private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data, String sql, List<Parameter> parameters) throws ConfigurationException, FormatterException {
   378 	private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
       
   379 		printHeader(formatter, header, sql, parameters);
       
   380 
       
   381 		for (Object[] row : data) {
       
   382 			printRow(formatter, row);
       
   383 		}
       
   384 
       
   385 		printFooter(formatter);
       
   386 	}
       
   387 
       
   388 	private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
   335 		formatter.writeStartStatement();
   389 		formatter.writeStartStatement();
   336 
       
   337 		if (sql != null) {
   390 		if (sql != null) {
   338 			formatter.writeQuery(sql);
   391 			formatter.writeQuery(sql);
   339 			if (parameters != null) {
   392 			if (parameters != null) {
   340 				formatter.writeParameters(parameters);
   393 				formatter.writeParameters(parameters);
   341 			}
   394 			}
   342 		}
   395 		}
   343 
       
   344 		formatter.writeStartResultSet(header);
   396 		formatter.writeStartResultSet(header);
   345 
   397 	}
   346 		for (Object[] row : data) {
   398 
   347 			formatter.writeStartRow();
   399 	private void printRow(Formatter formatter, Object[] row) {
   348 			for (Object cell : row) {
   400 		formatter.writeStartRow();
   349 				formatter.writeColumnValue(cell);
   401 		for (Object cell : row) {
   350 			}
   402 			formatter.writeColumnValue(cell);
   351 			formatter.writeEndRow();
   403 		}
   352 		}
   404 		formatter.writeEndRow();
   353 
   405 	}
       
   406 
       
   407 	private void printFooter(Formatter formatter) {
   354 		formatter.writeEndResultSet();
   408 		formatter.writeEndResultSet();
   355 		formatter.writeEndStatement();
   409 		formatter.writeEndStatement();
   356 	}
   410 	}
   357 
   411 
   358 	private Formatter getFormatter() throws ConfigurationException, FormatterException {
   412 	private Formatter getFormatter() throws ConfigurationException, FormatterException {
   395 	}
   449 	}
   396 
   450 
   397 	public enum InfoType {
   451 	public enum InfoType {
   398 
   452 
   399 		HELP {
   453 		HELP {
   400 			@Override
   454 					@Override
   401 			public void showInfo(InfoLister infoLister) {
   455 					public void showInfo(InfoLister infoLister) {
   402 				infoLister.printResource(Constants.HELP_FILE);
   456 						infoLister.printResource(Constants.HELP_FILE);
   403 			}
   457 					}
   404 		},
   458 				},
   405 		VERSION {
   459 		VERSION {
   406 			@Override
   460 					@Override
   407 			public void showInfo(InfoLister infoLister) {
   461 					public void showInfo(InfoLister infoLister) {
   408 				infoLister.printResource(Constants.VERSION_FILE);
   462 						infoLister.printResource(Constants.VERSION_FILE);
   409 			}
   463 					}
   410 		},
   464 				},
   411 		LICENSE {
   465 		LICENSE {
   412 			@Override
   466 					@Override
   413 			public void showInfo(InfoLister infoLister) {
   467 					public void showInfo(InfoLister infoLister) {
   414 				infoLister.printResource(Constants.LICENSE_FILE);
   468 						infoLister.printResource(Constants.LICENSE_FILE);
   415 			}
   469 					}
   416 		},
   470 				},
   417 		FORMATTERS {
   471 		FORMATTERS {
   418 			@Override
   472 					@Override
   419 			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   473 					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   420 				infoLister.listFormatters();
   474 						infoLister.listFormatters();
   421 			}
   475 					}
   422 		},
   476 				},
   423 		TYPES {
   477 		TYPES {
   424 			@Override
   478 					@Override
   425 			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   479 					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   426 				infoLister.listTypes();
   480 						infoLister.listTypes();
   427 			}
   481 					}
   428 		},
   482 				},
   429 		JDBC_DRIVERS {
   483 		JDBC_DRIVERS {
   430 			@Override
   484 					@Override
   431 			public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   485 					public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   432 				infoLister.listJdbcDrivers();
   486 						infoLister.listJdbcDrivers();
   433 			}
   487 					}
   434 		},
   488 				},
   435 		JDBC_PROPERTIES {
   489 		JDBC_PROPERTIES {
   436 			@Override
   490 					@Override
   437 			public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   491 					public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   438 				infoLister.listJdbcProperties();
   492 						infoLister.listJdbcProperties();
   439 			}
   493 					}
   440 		},
   494 				},
   441 		DATABASES {
   495 		DATABASES {
   442 			@Override
   496 					@Override
   443 			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   497 					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   444 				infoLister.listDatabases();
   498 						infoLister.listDatabases();
   445 			}
   499 					}
   446 		},
   500 				},
   447 		CONNECTION {
   501 		CONNECTION {
   448 			@Override
   502 					@Override
   449 			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   503 					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   450 				infoLister.testConnection();
   504 						infoLister.testConnections();
   451 			}
   505 					}
   452 		};
   506 				};
   453 
   507 
   454 		public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
   508 		public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
   455 	}
   509 	}
   456 }
   510 }