1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Mon Mar 04 17:06:42 2019 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,673 +0,0 @@
1.4 -/**
1.5 - * SQL-DK
1.6 - * Copyright © 2013 František Kučera (frantovo.cz)
1.7 - *
1.8 - * This program is free software: you can redistribute it and/or modify
1.9 - * it under the terms of the GNU General Public License as published by
1.10 - * the Free Software Foundation, either version 3 of the License, or
1.11 - * (at your option) any later version.
1.12 - *
1.13 - * This program is distributed in the hope that it will be useful,
1.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 - * GNU General Public License for more details.
1.17 - *
1.18 - * You should have received a copy of the GNU General Public License
1.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 - */
1.21 -package info.globalcode.sql.dk;
1.22 -
1.23 -import info.globalcode.sql.dk.configuration.CommandArgument;
1.24 -import info.globalcode.sql.dk.configuration.Configuration;
1.25 -import info.globalcode.sql.dk.configuration.ConfigurationException;
1.26 -import info.globalcode.sql.dk.configuration.ConfigurationProvider;
1.27 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
1.28 -import info.globalcode.sql.dk.configuration.FormatterDefinition;
1.29 -import info.globalcode.sql.dk.configuration.Properties;
1.30 -import info.globalcode.sql.dk.configuration.Property;
1.31 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
1.32 -import info.globalcode.sql.dk.configuration.TunnelDefinition;
1.33 -import info.globalcode.sql.dk.formatting.ColumnsHeader;
1.34 -import info.globalcode.sql.dk.formatting.CommonProperties;
1.35 -import info.globalcode.sql.dk.formatting.FakeSqlArray;
1.36 -import info.globalcode.sql.dk.formatting.Formatter;
1.37 -import info.globalcode.sql.dk.formatting.FormatterContext;
1.38 -import info.globalcode.sql.dk.formatting.FormatterException;
1.39 -import java.io.BufferedReader;
1.40 -import java.io.ByteArrayOutputStream;
1.41 -import java.io.InputStreamReader;
1.42 -import java.io.PrintStream;
1.43 -import java.sql.Array;
1.44 -import java.sql.Driver;
1.45 -import java.sql.DriverManager;
1.46 -import java.sql.DriverPropertyInfo;
1.47 -import java.sql.SQLException;
1.48 -import java.util.ArrayList;
1.49 -import java.util.Collections;
1.50 -import java.util.Comparator;
1.51 -import java.util.EnumSet;
1.52 -import java.util.HashMap;
1.53 -import java.util.HashSet;
1.54 -import java.util.List;
1.55 -import java.util.Map;
1.56 -import java.util.Map.Entry;
1.57 -import java.util.ServiceLoader;
1.58 -import java.util.Set;
1.59 -import java.util.concurrent.ExecutorService;
1.60 -import java.util.concurrent.Executors;
1.61 -import java.util.concurrent.TimeUnit;
1.62 -import java.util.logging.Level;
1.63 -import java.util.logging.LogRecord;
1.64 -import java.util.logging.Logger;
1.65 -import javax.sql.rowset.RowSetMetaDataImpl;
1.66 -
1.67 -/**
1.68 - * Displays info like help, version etc.
1.69 - *
1.70 - * @author Ing. František Kučera (frantovo.cz)
1.71 - */
1.72 -public class InfoLister {
1.73 -
1.74 - private static final Logger log = Logger.getLogger(InfoLister.class.getName());
1.75 - /**
1.76 - * Fake database name for output formatting
1.77 - */
1.78 - public static final String CONFIG_DB_NAME = "sqldk_configuration";
1.79 - private final PrintStream out;
1.80 - private final ConfigurationProvider configurationProvider;
1.81 - private final CLIOptions options;
1.82 - private Formatter formatter;
1.83 -
1.84 - public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
1.85 - this.out = out;
1.86 - this.configurationProvider = configurationProvider;
1.87 - this.options = options;
1.88 - }
1.89 -
1.90 - public void showInfo() throws ConfigurationException, FormatterException {
1.91 - EnumSet<InfoType> commands = options.getShowInfo();
1.92 -
1.93 - boolean formattinNeeded = false;
1.94 -
1.95 - for (InfoType infoType : commands) {
1.96 - switch (infoType) {
1.97 - case CONNECTION:
1.98 - case JDBC_DRIVERS:
1.99 - case JDBC_PROPERTIES:
1.100 - case DATABASES:
1.101 - case FORMATTERS:
1.102 - case FORMATTER_PROPERTIES:
1.103 - case TYPES:
1.104 - case JAVA_PROPERTIES:
1.105 - case ENVIRONMENT_VARIABLES:
1.106 - formattinNeeded = true;
1.107 - break;
1.108 - }
1.109 - }
1.110 -
1.111 - if (formattinNeeded) {
1.112 - try (Formatter f = getFormatter()) {
1.113 - formatter = f;
1.114 - formatter.writeStartBatch();
1.115 - DatabaseDefinition dd = new DatabaseDefinition();
1.116 - dd.setName(CONFIG_DB_NAME);
1.117 - formatter.writeStartDatabase(dd);
1.118 - showInfos(commands);
1.119 - formatter.writeEndDatabase();
1.120 - formatter.writeEndBatch();
1.121 - formatter.close();
1.122 - }
1.123 - } else {
1.124 - showInfos(commands);
1.125 - }
1.126 - }
1.127 -
1.128 - private void showInfos(EnumSet<InfoType> commands) throws ConfigurationException, FormatterException {
1.129 - for (InfoType infoType : commands) {
1.130 - infoType.showInfo(this);
1.131 - }
1.132 - }
1.133 -
1.134 - private void listJavaProperties() throws FormatterException, ConfigurationException {
1.135 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
1.136 - List<Object[]> data = new ArrayList<>();
1.137 - for (Entry<Object, Object> e : System.getProperties().entrySet()) {
1.138 - data.add(new Object[]{e.getKey(), e.getValue()});
1.139 - }
1.140 - printTable(formatter, header, "-- Java system properties", null, data, 0);
1.141 - }
1.142 -
1.143 - private void listEnvironmentVariables() throws FormatterException, ConfigurationException {
1.144 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
1.145 - List<Object[]> data = new ArrayList<>();
1.146 - for (Entry<String, String> e : System.getenv().entrySet()) {
1.147 - data.add(new Object[]{e.getKey(), e.getValue()});
1.148 - }
1.149 - printTable(formatter, header, "-- environment variables", null, data, 0);
1.150 - }
1.151 -
1.152 - private void listFormatters() throws ConfigurationException, FormatterException {
1.153 - ColumnsHeader header = constructHeader(
1.154 - new HeaderField("name", SQLType.VARCHAR),
1.155 - new HeaderField("built_in", SQLType.BOOLEAN),
1.156 - new HeaderField("default", SQLType.BOOLEAN),
1.157 - new HeaderField("class_name", SQLType.VARCHAR),
1.158 - new HeaderField("valid", SQLType.BOOLEAN));
1.159 - List<Object[]> data = new ArrayList<>();
1.160 -
1.161 - String defaultFormatter = configurationProvider.getConfiguration().getDefaultFormatter();
1.162 - defaultFormatter = defaultFormatter == null ? Configuration.DEFAULT_FORMATTER : defaultFormatter;
1.163 -
1.164 - for (FormatterDefinition fd : configurationProvider.getConfiguration().getBuildInFormatters()) {
1.165 - data.add(new Object[]{fd.getName(), true, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
1.166 - }
1.167 -
1.168 - for (FormatterDefinition fd : configurationProvider.getConfiguration().getFormatters()) {
1.169 - data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
1.170 - }
1.171 -
1.172 - printTable(formatter, header, "-- configured and built-in output formatters", null, data);
1.173 - }
1.174 -
1.175 - private boolean isInstantiable(FormatterDefinition fd) {
1.176 - try {
1.177 - try (ByteArrayOutputStream testStream = new ByteArrayOutputStream()) {
1.178 - fd.getInstance(new FormatterContext(testStream, new Properties(0)));
1.179 - return true;
1.180 - }
1.181 - } catch (Exception e) {
1.182 - log.log(Level.SEVERE, "Unable to create an instance of formatter: " + fd.getName(), e);
1.183 - return false;
1.184 - }
1.185 - }
1.186 -
1.187 - private void listFormatterProperties() throws FormatterException, ConfigurationException {
1.188 - for (String formatterName : options.getFormatterNamesToListProperties()) {
1.189 - listFormatterProperties(formatterName);
1.190 - }
1.191 - }
1.192 -
1.193 - private void listFormatterProperties(String formatterName) throws FormatterException, ConfigurationException {
1.194 - FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
1.195 - try {
1.196 -
1.197 - // currently only for debugging purposes
1.198 - // TODO: introduce --info-lister-property or generic filtering capability in printTable() ?
1.199 - boolean printDeclaredIn = options.getFormatterProperties().getBoolean("InfoLister:print:declared_in", false);
1.200 -
1.201 - List<HeaderField> headerFields = new ArrayList<>();
1.202 - headerFields.add(new HeaderField("name", SQLType.VARCHAR));
1.203 - headerFields.add(new HeaderField("type", SQLType.VARCHAR));
1.204 - headerFields.add(new HeaderField("default", SQLType.VARCHAR));
1.205 - headerFields.add(new HeaderField("description", SQLType.VARCHAR));
1.206 - if (printDeclaredIn) {
1.207 - headerFields.add(new HeaderField("declared_in", SQLType.VARCHAR));
1.208 - }
1.209 -
1.210 - ColumnsHeader header = constructHeader(headerFields.toArray(new HeaderField[0]));
1.211 -
1.212 - Map<String, Object[]> data = new HashMap<>();
1.213 - Class<Formatter> formatterClass = (Class<Formatter>) Class.forName(fd.getClassName());
1.214 - List<Class<? extends Formatter>> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class);
1.215 - Collections.reverse(hierarchy);
1.216 - hierarchy.stream().forEach((c) -> {
1.217 - for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) {
1.218 - data.put(p.name(), propertyDeclarationToRow(p, c, printDeclaredIn));
1.219 - }
1.220 - });
1.221 -
1.222 - List<Parameter> parameters = new ArrayList<>();
1.223 - parameters.add(new NamedParameter("formatter", formatterName, SQLType.VARCHAR));
1.224 -
1.225 - printTable(formatter, header, "-- formatter properties", parameters, new ArrayList<>(data.values()));
1.226 - } catch (ClassNotFoundException e) {
1.227 - throw new ConfigurationException("Unable to find class " + fd.getClassName() + " of formatter" + fd.getName(), e);
1.228 - }
1.229 - }
1.230 -
1.231 - private static Object[] propertyDeclarationToRow(PropertyDeclaration p, Class formatterClass, boolean printDeclaredIn) {
1.232 - List list = new ArrayList();
1.233 -
1.234 - list.add(p.name());
1.235 - list.add(CommonProperties.getSimpleTypeName(p.type()));
1.236 - list.add(p.defaultValue());
1.237 - list.add(p.description());
1.238 - if (printDeclaredIn) {
1.239 - list.add(formatterClass.getName());
1.240 - }
1.241 -
1.242 - return list.toArray();
1.243 - }
1.244 -
1.245 - private void listTypes() throws FormatterException, ConfigurationException {
1.246 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("code", SQLType.INTEGER));
1.247 - List<Object[]> data = new ArrayList<>();
1.248 - for (SQLType sqlType : SQLType.values()) {
1.249 - data.add(new Object[]{sqlType.name(), sqlType.getCode()});
1.250 - }
1.251 - printTable(formatter, header, "-- data types", null, data);
1.252 - log.log(Level.INFO, "Type names in --types option are case insensitive");
1.253 - }
1.254 -
1.255 - private void listDatabases() throws ConfigurationException, FormatterException {
1.256 - ColumnsHeader header = constructHeader(
1.257 - new HeaderField("database_name", SQLType.VARCHAR),
1.258 - new HeaderField("user_name", SQLType.VARCHAR),
1.259 - new HeaderField("database_url", SQLType.VARCHAR));
1.260 - List<Object[]> data = new ArrayList<>();
1.261 -
1.262 - final List<DatabaseDefinition> configuredDatabases = configurationProvider.getConfiguration().getDatabases();
1.263 - if (configuredDatabases.isEmpty()) {
1.264 - log.log(Level.WARNING, "No databases are configured.");
1.265 - } else {
1.266 - for (DatabaseDefinition dd : configuredDatabases) {
1.267 - data.add(new Object[]{dd.getName(), dd.getUserName(), dd.getUrl()});
1.268 -
1.269 - final TunnelDefinition tunnel = dd.getTunnel();
1.270 - if (tunnel != null) {
1.271 - log.log(Level.INFO, "Tunnel command: {0}", tunnel.getCommand());
1.272 - for (CommandArgument ca : Functions.notNull(tunnel.getArguments())) {
1.273 - log.log(Level.INFO, "\targument: {0}/{1}", new Object[]{ca.getType(), ca.getValue()});
1.274 - }
1.275 - }
1.276 -
1.277 - }
1.278 - }
1.279 -
1.280 - printTable(formatter, header, "-- configured databases", null, data);
1.281 - }
1.282 -
1.283 - private void listJdbcDrivers() throws FormatterException, ConfigurationException {
1.284 - ColumnsHeader header = constructHeader(
1.285 - new HeaderField("class", SQLType.VARCHAR),
1.286 - new HeaderField("version", SQLType.VARCHAR),
1.287 - new HeaderField("major", SQLType.INTEGER),
1.288 - new HeaderField("minor", SQLType.INTEGER),
1.289 - new HeaderField("jdbc_compliant", SQLType.BOOLEAN));
1.290 - List<Object[]> data = new ArrayList<>();
1.291 -
1.292 - final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
1.293 - for (Driver d : drivers) {
1.294 - data.add(new Object[]{
1.295 - d.getClass().getName(),
1.296 - d.getMajorVersion() + "." + d.getMinorVersion(),
1.297 - d.getMajorVersion(),
1.298 - d.getMinorVersion(),
1.299 - d.jdbcCompliant()
1.300 - });
1.301 - }
1.302 -
1.303 - printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
1.304 - }
1.305 -
1.306 - private void listJdbcProperties() throws FormatterException, ConfigurationException {
1.307 - for (String dbName : options.getDatabaseNamesToListProperties()) {
1.308 - ColumnsHeader header = constructHeader(
1.309 - new HeaderField("property_name", SQLType.VARCHAR),
1.310 - new HeaderField("required", SQLType.BOOLEAN),
1.311 - new HeaderField("choices", SQLType.ARRAY),
1.312 - new HeaderField("configured_value", SQLType.VARCHAR),
1.313 - new HeaderField("description", SQLType.VARCHAR));
1.314 - List<Object[]> data = new ArrayList<>();
1.315 -
1.316 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
1.317 -
1.318 - Driver driver = findDriver(dd);
1.319 -
1.320 - if (driver == null) {
1.321 - log.log(Level.WARNING, "No JDBC driver was found for DB: {0} with URL: {1}", new Object[]{dd.getName(), dd.getUrl()});
1.322 - } else {
1.323 - log.log(Level.INFO, "For DB: {0} was found JDBC driver: {1}", new Object[]{dd.getName(), driver.getClass().getName()});
1.324 -
1.325 - try {
1.326 - DriverPropertyInfo[] propertyInfos = driver.getPropertyInfo(dd.getUrl(), dd.getProperties().getJavaProperties());
1.327 -
1.328 - Set<String> standardProperties = new HashSet<>();
1.329 -
1.330 - for (DriverPropertyInfo pi : propertyInfos) {
1.331 - Array choices = new FakeSqlArray(pi.choices, SQLType.VARCHAR);
1.332 - data.add(new Object[]{
1.333 - pi.name,
1.334 - pi.required,
1.335 - choices.getArray() == null ? "" : choices,
1.336 - pi.value == null ? "" : pi.value,
1.337 - pi.description
1.338 - });
1.339 - standardProperties.add(pi.name);
1.340 - }
1.341 -
1.342 - for (Property p : dd.getProperties()) {
1.343 - if (!standardProperties.contains(p.getName())) {
1.344 - data.add(new Object[]{
1.345 - p.getName(),
1.346 - "",
1.347 - "",
1.348 - p.getValue(),
1.349 - ""
1.350 - });
1.351 - log.log(Level.WARNING, "Your configuration contains property „{0}“ not declared by the JDBC driver.", p.getName());
1.352 - }
1.353 - }
1.354 -
1.355 - } catch (SQLException e) {
1.356 - log.log(Level.WARNING, "Error during getting property infos.", e);
1.357 - }
1.358 -
1.359 - List<Parameter> parameters = new ArrayList<>();
1.360 - parameters.add(new NamedParameter("database", dbName, SQLType.VARCHAR));
1.361 - parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
1.362 - parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
1.363 - parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
1.364 -
1.365 - printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
1.366 - }
1.367 - }
1.368 -
1.369 - }
1.370 -
1.371 - private Driver findDriver(DatabaseDefinition dd) {
1.372 - final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
1.373 - for (Driver d : drivers) {
1.374 - try {
1.375 - if (d.acceptsURL(dd.getUrl())) {
1.376 - return d;
1.377 - }
1.378 - } catch (SQLException e) {
1.379 - log.log(Level.WARNING, "Error during finding JDBC driver for: " + dd.getName(), e);
1.380 - }
1.381 - }
1.382 - return null;
1.383 - }
1.384 -
1.385 - /**
1.386 - * Parallelism for connection testing – maximum concurrent database connections.
1.387 - */
1.388 - private static final int TESTING_THREAD_COUNT = 64;
1.389 - /**
1.390 - * Time limit for all connection testing threads – particular timeouts per connection will be
1.391 - * much smaller.
1.392 - */
1.393 - private static final long TESTING_AWAIT_LIMIT = 1;
1.394 - private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
1.395 -
1.396 - private void testConnections() throws FormatterException, ConfigurationException {
1.397 - ColumnsHeader header = constructHeader(
1.398 - new HeaderField("database_name", SQLType.VARCHAR),
1.399 - new HeaderField("configured", SQLType.BOOLEAN),
1.400 - new HeaderField("connected", SQLType.BOOLEAN),
1.401 - new HeaderField("product_name", SQLType.VARCHAR),
1.402 - new HeaderField("product_version", SQLType.VARCHAR));
1.403 -
1.404 - log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
1.405 -
1.406 - ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
1.407 -
1.408 - final Formatter currentFormatter = formatter;
1.409 -
1.410 - printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
1.411 -
1.412 - for (final String dbName : options.getDatabaseNamesToTest()) {
1.413 - preloadDriver(dbName);
1.414 - }
1.415 -
1.416 - for (final String dbName : options.getDatabaseNamesToTest()) {
1.417 - es.submit(() -> {
1.418 - final Object[] row = testConnection(dbName);
1.419 - synchronized (currentFormatter) {
1.420 - printRow(currentFormatter, row);
1.421 - }
1.422 - }
1.423 - );
1.424 - }
1.425 -
1.426 - es.shutdown();
1.427 -
1.428 - try {
1.429 - log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
1.430 - boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
1.431 - if (finished) {
1.432 - log.log(Level.FINEST, "All testing threads finished in time limit.");
1.433 - } else {
1.434 - throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
1.435 - }
1.436 - } catch (InterruptedException e) {
1.437 - throw new FormatterException("Interrupted while waiting for test results", e);
1.438 - }
1.439 -
1.440 - printFooter(currentFormatter);
1.441 - }
1.442 -
1.443 - /**
1.444 - * JDBC driver classes should be preloaded in single thread to avoid deadlocks while doing
1.445 - * {@linkplain DriverManager#registerDriver(java.sql.Driver)} during parallel connections.
1.446 - *
1.447 - * @param dbName
1.448 - */
1.449 - private void preloadDriver(String dbName) {
1.450 - try {
1.451 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
1.452 - Driver driver = findDriver(dd);
1.453 - if (driver == null) {
1.454 - log.log(Level.WARNING, "No Driver found for DB: {0}", dbName);
1.455 - } else {
1.456 - log.log(Level.FINEST, "Driver preloading for DB: {0} was successfull", dbName);
1.457 - }
1.458 - } catch (Exception e) {
1.459 - LogRecord r = new LogRecord(Level.WARNING, "Failed to preload the Driver for DB: {0}");
1.460 - r.setParameters(new Object[]{dbName});
1.461 - r.setThrown(e);
1.462 - log.log(r);
1.463 - }
1.464 - }
1.465 -
1.466 - private Object[] testConnection(String dbName) {
1.467 - log.log(Level.FINE, "Testing connection to database: {0}", dbName);
1.468 -
1.469 - boolean succesfullyConnected = false;
1.470 - boolean succesfullyConfigured = false;
1.471 - String productName = null;
1.472 - String productVersion = null;
1.473 -
1.474 - try {
1.475 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
1.476 - log.log(Level.FINE, "Database definition was loaded from configuration");
1.477 - succesfullyConfigured = true;
1.478 - try (DatabaseConnection dc = dd.connect(options.getDatabaseProperties())) {
1.479 - succesfullyConnected = dc.test();
1.480 - productName = dc.getProductName();
1.481 - productVersion = dc.getProductVersion();
1.482 - }
1.483 - log.log(Level.FINE, "Database connection test was successful");
1.484 - } catch (ConfigurationException | SQLException | RuntimeException e) {
1.485 - log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
1.486 - }
1.487 -
1.488 - return new Object[]{dbName, succesfullyConfigured, succesfullyConnected, productName, productVersion};
1.489 - }
1.490 -
1.491 - private void printResource(String fileName) {
1.492 - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName)))) {
1.493 - while (true) {
1.494 - String line = reader.readLine();
1.495 - if (line == null) {
1.496 - break;
1.497 - } else {
1.498 - println(line);
1.499 - }
1.500 - }
1.501 - } catch (Exception e) {
1.502 - log.log(Level.SEVERE, "Unable to print this info. Please see our website for it: " + Constants.WEBSITE, e);
1.503 - }
1.504 - }
1.505 -
1.506 - private void println(String line) {
1.507 - out.println(line);
1.508 - }
1.509 -
1.510 - private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
1.511 - printTable(formatter, header, sql, parameters, data, null);
1.512 - }
1.513 -
1.514 - private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data, final Integer sortByColumn) throws ConfigurationException, FormatterException {
1.515 - printHeader(formatter, header, sql, parameters);
1.516 -
1.517 - if (sortByColumn != null) {
1.518 - Collections.sort(data, new Comparator<Object[]>() {
1.519 -
1.520 - @Override
1.521 - public int compare(Object[] o1, Object[] o2) {
1.522 - String s1 = String.valueOf(o1[sortByColumn]);
1.523 - String s2 = String.valueOf(o2[sortByColumn]);
1.524 - return s1.compareTo(s2);
1.525 - }
1.526 - });
1.527 - }
1.528 -
1.529 - for (Object[] row : data) {
1.530 - printRow(formatter, row);
1.531 - }
1.532 -
1.533 - printFooter(formatter);
1.534 - }
1.535 -
1.536 - private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
1.537 - formatter.writeStartStatement();
1.538 - if (sql != null) {
1.539 - formatter.writeQuery(sql);
1.540 - if (parameters != null) {
1.541 - formatter.writeParameters(parameters);
1.542 - }
1.543 - }
1.544 - formatter.writeStartResultSet(header);
1.545 - }
1.546 -
1.547 - private void printRow(Formatter formatter, Object[] row) {
1.548 - formatter.writeStartRow();
1.549 - for (Object cell : row) {
1.550 - formatter.writeColumnValue(cell);
1.551 - }
1.552 - formatter.writeEndRow();
1.553 - }
1.554 -
1.555 - private void printFooter(Formatter formatter) {
1.556 - formatter.writeEndResultSet();
1.557 - formatter.writeEndStatement();
1.558 - }
1.559 -
1.560 - private Formatter getFormatter() throws ConfigurationException, FormatterException {
1.561 - String formatterName = options.getFormatterName();
1.562 - formatterName = formatterName == null ? Configuration.DEFAULT_FORMATTER_PREFETCHING : formatterName;
1.563 - FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
1.564 - FormatterContext context = new FormatterContext(out, options.getFormatterProperties());
1.565 - return fd.getInstance(context);
1.566 - }
1.567 -
1.568 - private ColumnsHeader constructHeader(HeaderField... fields) throws FormatterException {
1.569 - try {
1.570 - RowSetMetaDataImpl metaData = new RowSetMetaDataImpl();
1.571 - metaData.setColumnCount(fields.length);
1.572 -
1.573 - for (int i = 0; i < fields.length; i++) {
1.574 - HeaderField hf = fields[i];
1.575 - int sqlIndex = i + 1;
1.576 - metaData.setColumnName(sqlIndex, hf.name);
1.577 - metaData.setColumnLabel(sqlIndex, hf.name);
1.578 - metaData.setColumnType(sqlIndex, hf.type.getCode());
1.579 - metaData.setColumnTypeName(sqlIndex, hf.type.name());
1.580 - }
1.581 -
1.582 - return new ColumnsHeader(metaData);
1.583 - } catch (SQLException e) {
1.584 - throw new FormatterException("Error while constructing table headers", e);
1.585 - }
1.586 - }
1.587 -
1.588 - private static class HeaderField {
1.589 -
1.590 - String name;
1.591 - SQLType type;
1.592 -
1.593 - public HeaderField(String name, SQLType type) {
1.594 - this.name = name;
1.595 - this.type = type;
1.596 - }
1.597 - }
1.598 -
1.599 - public enum InfoType {
1.600 -
1.601 - HELP {
1.602 - @Override
1.603 - public void showInfo(InfoLister infoLister) {
1.604 - infoLister.printResource(Constants.HELP_FILE);
1.605 - }
1.606 - },
1.607 - VERSION {
1.608 - @Override
1.609 - public void showInfo(InfoLister infoLister) {
1.610 - infoLister.printResource(Constants.VERSION_FILE);
1.611 - }
1.612 - },
1.613 - LICENSE {
1.614 - @Override
1.615 - public void showInfo(InfoLister infoLister) {
1.616 - infoLister.printResource(Constants.LICENSE_FILE);
1.617 - }
1.618 - },
1.619 - JAVA_PROPERTIES {
1.620 - @Override
1.621 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.622 - infoLister.listJavaProperties();
1.623 - }
1.624 - },
1.625 - ENVIRONMENT_VARIABLES {
1.626 - @Override
1.627 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.628 - infoLister.listEnvironmentVariables();
1.629 - }
1.630 - },
1.631 - FORMATTERS {
1.632 - @Override
1.633 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.634 - infoLister.listFormatters();
1.635 - }
1.636 - },
1.637 - FORMATTER_PROPERTIES {
1.638 - @Override
1.639 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.640 - infoLister.listFormatterProperties();
1.641 - }
1.642 - },
1.643 - TYPES {
1.644 - @Override
1.645 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.646 - infoLister.listTypes();
1.647 - }
1.648 - },
1.649 - JDBC_DRIVERS {
1.650 - @Override
1.651 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.652 - infoLister.listJdbcDrivers();
1.653 - }
1.654 - },
1.655 - JDBC_PROPERTIES {
1.656 - @Override
1.657 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
1.658 - infoLister.listJdbcProperties();
1.659 - }
1.660 - },
1.661 - DATABASES {
1.662 - @Override
1.663 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.664 - infoLister.listDatabases();
1.665 - }
1.666 - },
1.667 - CONNECTION {
1.668 - @Override
1.669 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
1.670 - infoLister.testConnections();
1.671 - }
1.672 - };
1.673 -
1.674 - public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
1.675 - }
1.676 -}