# HG changeset patch # User František Kučera # Date 1389816372 -3600 # Node ID 9632b23df30c18cd2d6491a4ee70a3a17d6c49ae # Parent 770b5009ec421ca5bd79cb23203327be578aeea9 InfoLister: list configured and configurable JDBC driver properties – option: --list-jdbc-properties diff -r 770b5009ec42 -r 9632b23df30c java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java Wed Jan 15 18:15:55 2014 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java Wed Jan 15 21:06:12 2014 +0100 @@ -46,6 +46,7 @@ private String sql; private String databaseName; private Set databaseNamesToTest = new HashSet<>(); + private Set databaseNamesToListProperties = new HashSet<>(); private String namePrefix = DEFAULT_NAME_PREFIX; private String nameSuffix = DEFAULT_NAME_SUFFIX; private String formatterName; @@ -95,6 +96,9 @@ if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) { e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested.")); } + if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) { + e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed.")); + } } if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) { @@ -238,10 +242,18 @@ return databaseNamesToTest; } - public void addDatabaseNamesToTest(String databaseNameToTest) { - this.databaseNamesToTest.add(databaseNameToTest); + public void addDatabaseNameToTest(String name) { + databaseNamesToTest.add(name); } + public Set getDatabaseNamesToListProperties() { + return databaseNamesToListProperties; + } + + public void addDatabaseNameToListProperties(String name) { + databaseNamesToListProperties.add(name); + } + public SQLCommand getSQLCommand() { if (namedParameters.isEmpty()) { return new SQLCommandNumbered(sql, numberedParameters); diff -r 770b5009ec42 -r 9632b23df30c java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java Wed Jan 15 18:15:55 2014 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java Wed Jan 15 21:06:12 2014 +0100 @@ -128,12 +128,16 @@ case Tokens.INFO_JDBC_DRIVERS: options.addShowInfo(InfoType.JDBC_DRIVERS); break; + case Tokens.INFO_JDBC_PROPERTIES: + options.addShowInfo(InfoType.JDBC_PROPERTIES); + options.addDatabaseNameToListProperties(fetchNext(args, ++i)); + break; case Tokens.INFO_DATABASES: options.addShowInfo(InfoType.DATABASES); break; case Tokens.INFO_CONNECTION: options.addShowInfo(InfoType.CONNECTION); - options.addDatabaseNamesToTest(fetchNext(args, ++i)); + options.addDatabaseNameToTest(fetchNext(args, ++i)); break; default: throw new CLIParserException("Unknown option: " + arg); @@ -170,6 +174,7 @@ public static final String INFO_FORMATTERS = "--list-formatters"; // bash-completion:option // help: print list of available formatters public static final String INFO_TYPES = "--list-types"; // bash-completion:option // help: print list of available data types public static final String INFO_JDBC_DRIVERS = "--list-jdbc-drivers"; // bash-completion:option // help: list of available JDBC drivers + public static final String INFO_JDBC_PROPERTIES = "--list-jdbc-properties"; // bash-completion:option // help: list of available JDBC properties for given database public static final String INFO_DATABASES = "--list-databases"; // bash-completion:option // help: print list of configured databases public static final String INFO_CONNECTION = "--test-connection"; // bash-completion:option // help: test connection to particular database diff -r 770b5009ec42 -r 9632b23df30c java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Wed Jan 15 18:15:55 2014 +0100 +++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Wed Jan 15 21:06:12 2014 +0100 @@ -22,19 +22,25 @@ import info.globalcode.sql.dk.configuration.ConfigurationProvider; import info.globalcode.sql.dk.configuration.DatabaseDefinition; import info.globalcode.sql.dk.configuration.FormatterDefinition; +import info.globalcode.sql.dk.configuration.Property; import info.globalcode.sql.dk.formatting.ColumnsHeader; +import info.globalcode.sql.dk.formatting.FakeSqlArray; import info.globalcode.sql.dk.formatting.Formatter; import info.globalcode.sql.dk.formatting.FormatterContext; import info.globalcode.sql.dk.formatting.FormatterException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; +import java.sql.Array; import java.sql.Driver; +import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.util.ArrayList; import java.util.EnumSet; +import java.util.HashSet; import java.util.List; import java.util.ServiceLoader; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.sql.rowset.RowSetMetaDataImpl; @@ -47,6 +53,10 @@ public class InfoLister { private static final Logger log = Logger.getLogger(InfoLister.class.getName()); + /** + * Fake database name for output formatting + */ + public static final String CONFIG_DB_NAME = "sqldk_configuration"; private PrintStream out; private ConfigurationProvider configurationProvider; private CLIOptions options; @@ -67,6 +77,7 @@ switch (infoType) { case CONNECTION: case JDBC_DRIVERS: + case JDBC_PROPERTIES: case DATABASES: case FORMATTERS: case TYPES: @@ -79,10 +90,10 @@ try (Formatter f = getFormatter()) { formatter = f; formatter.writeStartBatch(); - formatter.writeStartDatabase(new DatabaseDefinition()); - formatter.writeStartStatement(); + DatabaseDefinition dd = new DatabaseDefinition(); + dd.setName(CONFIG_DB_NAME); + formatter.writeStartDatabase(dd); showInfos(commands); - formatter.writeEndStatement(); formatter.writeEndDatabase(); formatter.writeEndBatch(); formatter.close(); @@ -117,7 +128,7 @@ data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName()}); } - printTable(formatter, header, data); + printTable(formatter, header, data, "-- configured and built-in output formatters", null); } @@ -128,7 +139,7 @@ for (SQLType sqlType : SQLType.values()) { data.add(new Object[]{sqlType.name(), sqlType.getCode()}); } - printTable(formatter, header, data); + printTable(formatter, header, data, "-- data types", null); log.log(Level.INFO, "Type names in --types option are case insensitive"); } @@ -148,7 +159,7 @@ } } - printTable(formatter, header, data); + printTable(formatter, header, data, "-- configured databases", null); } public void listJdbcDrivers() throws FormatterException, ConfigurationException { @@ -167,11 +178,90 @@ d.getMajorVersion() + "." + d.getMinorVersion(), d.getMajorVersion(), d.getMinorVersion(), - d.jdbcCompliant()}); + d.jdbcCompliant() + }); } - printTable(formatter, header, data); + printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null); + } + public void listJdbcProperties() throws FormatterException, ConfigurationException { + for (String dbName : options.getDatabaseNamesToListProperties()) { + ColumnsHeader header = constructHeader( + new HeaderField("property_name", SQLType.VARCHAR), + new HeaderField("required", SQLType.BOOLEAN), + new HeaderField("choices", SQLType.ARRAY), + new HeaderField("configured_value", SQLType.VARCHAR), + new HeaderField("description", SQLType.VARCHAR)); + List data = new ArrayList<>(); + + DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName); + + Driver driver = findDriver(dd); + + if (driver == null) { + log.log(Level.WARNING, "No JDBC driver was found for DB: {0} with URL: {1}", new Object[]{dd.getName(), dd.getUrl()}); + } else { + log.log(Level.INFO, "For DB: {0} was found JDBC driver: {1}", new Object[]{dd.getName(), driver.getClass().getName()}); + + try { + DriverPropertyInfo[] propertyInfos = driver.getPropertyInfo(dd.getUrl(), dd.getProperties().getJavaProperties()); + + Set standardProperties = new HashSet<>(); + + for (DriverPropertyInfo pi : propertyInfos) { + Array choices = new FakeSqlArray(pi.choices, SQLType.VARCHAR); + data.add(new Object[]{ + pi.name, + pi.required, + choices.getArray() == null ? "" : choices, + pi.value == null ? "" : pi.value, + pi.description + }); + standardProperties.add(pi.name); + } + + for (Property p : dd.getProperties()) { + if (!standardProperties.contains(p.getName())) { + data.add(new Object[]{ + p.getName(), + "", + "", + p.getValue(), + "" + }); + log.log(Level.WARNING, "Your configuration contains property „{0}“ not declared by the JDBC driver.", p.getName()); + } + } + + } catch (SQLException e) { + log.log(Level.WARNING, "Error during getting property infos.", e); + } + + List parameters = new ArrayList<>(); + parameters.add(new NamedParameter("databgase", dbName, SQLType.VARCHAR)); + parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR)); + 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); + } + } + + } + + private Driver findDriver(DatabaseDefinition dd) { + final ServiceLoader drivers = ServiceLoader.load(Driver.class); + for (Driver d : drivers) { + try { + if (d.acceptsURL(dd.getUrl())) { + return d; + } + } catch (SQLException e) { + log.log(Level.WARNING, "Error during finding JDBC driver for: " + dd.getName(), e); + } + } + return null; } public void testConnection() throws FormatterException, ConfigurationException { @@ -185,7 +275,7 @@ data.add(testConnection(dbName)); } - printTable(formatter, header, data); + printTable(formatter, header, data, "-- database configuration and connectivity test", null); } public Object[] testConnection(String dbName) { @@ -228,7 +318,16 @@ out.println(line); } - private void printTable(Formatter formatter, ColumnsHeader header, List data) throws ConfigurationException, FormatterException { + private void printTable(Formatter formatter, ColumnsHeader header, List data, String sql, List parameters) throws ConfigurationException, FormatterException { + formatter.writeStartStatement(); + + if (sql != null) { + formatter.writeQuery(sql); + if (parameters != null) { + formatter.writeParameters(parameters); + } + } + formatter.writeStartResultSet(header); for (Object[] row : data) { @@ -240,6 +339,7 @@ } formatter.writeEndResultSet(); + formatter.writeEndStatement(); } private Formatter getFormatter() throws ConfigurationException, FormatterException { @@ -319,6 +419,12 @@ infoLister.listJdbcDrivers(); } }, + JDBC_PROPERTIES { + @Override + public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException { + infoLister.listJdbcProperties(); + } + }, DATABASES { @Override public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException { diff -r 770b5009ec42 -r 9632b23df30c java/sql-dk/src/info/globalcode/sql/dk/formatting/FakeSqlArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/FakeSqlArray.java Wed Jan 15 21:06:12 2014 +0100 @@ -0,0 +1,96 @@ +/** + * SQL-DK + * Copyright © 2014 František Kučera (frantovo.cz) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package info.globalcode.sql.dk.formatting; + +import info.globalcode.sql.dk.SQLType; +import java.sql.Array; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +/** + * Fake SQL array, for formatting purposes only + * + * @author Ing. František Kučera (frantovo.cz) + */ +public class FakeSqlArray implements Array { + + private static final UnsupportedOperationException exception = new UnsupportedOperationException("This is just a fake SQL array."); + private final Object[] data; + private final SQLType baseType; + + public FakeSqlArray(Object[] data, SQLType baseType) { + this.data = data; + this.baseType = baseType; + } + + @Override + public String getBaseTypeName() throws SQLException { + return baseType.name(); + } + + @Override + public int getBaseType() throws SQLException { + return baseType.getCode(); + } + + @Override + public Object getArray() throws SQLException { + return data; + } + + @Override + public Object getArray(Map> map) throws SQLException { + throw exception; + } + + @Override + public Object getArray(long index, int count) throws SQLException { + throw exception; + } + + @Override + public Object getArray(long index, int count, Map> map) throws SQLException { + throw exception; + } + + @Override + public ResultSet getResultSet() throws SQLException { + throw exception; + } + + @Override + public ResultSet getResultSet(Map> map) throws SQLException { + throw exception; + } + + @Override + public ResultSet getResultSet(long index, int count) throws SQLException { + throw exception; + } + + @Override + public ResultSet getResultSet(long index, int count, Map> map) throws SQLException { + throw exception; + } + + @Override + public void free() throws SQLException { + throw exception; + } +} diff -r 770b5009ec42 -r 9632b23df30c scripts/bash_completion.pl --- a/scripts/bash_completion.pl Wed Jan 15 18:15:55 2014 +0100 +++ b/scripts/bash_completion.pl Wed Jan 15 21:06:12 2014 +0100 @@ -50,7 +50,7 @@ prev=${COMP_WORDS[COMP_CWORD-1]} case "$prev" in - --db | --test-connection) + --db | --test-connection | --list-jdbc-properties) if [ -f '.$databasesFile.' ]; then COMPREPLY=( $( compgen -W " $( cat '.$databasesFile.' ) " -- $cur ) ) return 0