InfoLister: list configured and configurable JDBC driver properties – option: --list-jdbc-properties v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Wed, 15 Jan 2014 21:06:12 +0100
branchv_0
changeset 1599632b23df30c
parent 158 770b5009ec42
child 160 84ea4a819fb2
InfoLister: list configured and configurable JDBC driver properties – option: --list-jdbc-properties
java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java
java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java
java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java
java/sql-dk/src/info/globalcode/sql/dk/formatting/FakeSqlArray.java
scripts/bash_completion.pl
     1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java	Wed Jan 15 18:15:55 2014 +0100
     1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java	Wed Jan 15 21:06:12 2014 +0100
     1.3 @@ -46,6 +46,7 @@
     1.4  	private String sql;
     1.5  	private String databaseName;
     1.6  	private Set<String> databaseNamesToTest = new HashSet<>();
     1.7 +	private Set<String> databaseNamesToListProperties = new HashSet<>();
     1.8  	private String namePrefix = DEFAULT_NAME_PREFIX;
     1.9  	private String nameSuffix = DEFAULT_NAME_SUFFIX;
    1.10  	private String formatterName;
    1.11 @@ -95,6 +96,9 @@
    1.12  			if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) {
    1.13  				e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested."));
    1.14  			}
    1.15 +			if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) {
    1.16 +				e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed."));
    1.17 +			}
    1.18  		}
    1.19  
    1.20  		if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) {
    1.21 @@ -238,10 +242,18 @@
    1.22  		return databaseNamesToTest;
    1.23  	}
    1.24  
    1.25 -	public void addDatabaseNamesToTest(String databaseNameToTest) {
    1.26 -		this.databaseNamesToTest.add(databaseNameToTest);
    1.27 +	public void addDatabaseNameToTest(String name) {
    1.28 +		databaseNamesToTest.add(name);
    1.29  	}
    1.30  
    1.31 +	public Set<String> getDatabaseNamesToListProperties() {
    1.32 +		return databaseNamesToListProperties;
    1.33 +	}
    1.34 +
    1.35 +	public void addDatabaseNameToListProperties(String name) {
    1.36 +		databaseNamesToListProperties.add(name);
    1.37 +	}
    1.38 +	
    1.39  	public SQLCommand getSQLCommand() {
    1.40  		if (namedParameters.isEmpty()) {
    1.41  			return new SQLCommandNumbered(sql, numberedParameters);
     2.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java	Wed Jan 15 18:15:55 2014 +0100
     2.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java	Wed Jan 15 21:06:12 2014 +0100
     2.3 @@ -128,12 +128,16 @@
     2.4  				case Tokens.INFO_JDBC_DRIVERS:
     2.5  					options.addShowInfo(InfoType.JDBC_DRIVERS);
     2.6  					break;
     2.7 +				case Tokens.INFO_JDBC_PROPERTIES:
     2.8 +					options.addShowInfo(InfoType.JDBC_PROPERTIES);
     2.9 +					options.addDatabaseNameToListProperties(fetchNext(args, ++i));
    2.10 +					break;
    2.11  				case Tokens.INFO_DATABASES:
    2.12  					options.addShowInfo(InfoType.DATABASES);
    2.13  					break;
    2.14  				case Tokens.INFO_CONNECTION:
    2.15  					options.addShowInfo(InfoType.CONNECTION);
    2.16 -					options.addDatabaseNamesToTest(fetchNext(args, ++i));
    2.17 +					options.addDatabaseNameToTest(fetchNext(args, ++i));
    2.18  					break;
    2.19  				default:
    2.20  					throw new CLIParserException("Unknown option: " + arg);
    2.21 @@ -170,6 +174,7 @@
    2.22  		public static final String INFO_FORMATTERS = "--list-formatters"; // bash-completion:option // help: print list of available formatters
    2.23  		public static final String INFO_TYPES = "--list-types"; // bash-completion:option // help: print list of available data types
    2.24  		public static final String INFO_JDBC_DRIVERS = "--list-jdbc-drivers"; // bash-completion:option // help: list of available JDBC drivers
    2.25 +		public static final String INFO_JDBC_PROPERTIES = "--list-jdbc-properties"; // bash-completion:option // help: list of available JDBC properties for given database
    2.26  		public static final String INFO_DATABASES = "--list-databases"; // bash-completion:option // help: print list of configured databases
    2.27  		public static final String INFO_CONNECTION = "--test-connection"; // bash-completion:option // help: test connection to particular database
    2.28  
     3.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java	Wed Jan 15 18:15:55 2014 +0100
     3.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java	Wed Jan 15 21:06:12 2014 +0100
     3.3 @@ -22,19 +22,25 @@
     3.4  import info.globalcode.sql.dk.configuration.ConfigurationProvider;
     3.5  import info.globalcode.sql.dk.configuration.DatabaseDefinition;
     3.6  import info.globalcode.sql.dk.configuration.FormatterDefinition;
     3.7 +import info.globalcode.sql.dk.configuration.Property;
     3.8  import info.globalcode.sql.dk.formatting.ColumnsHeader;
     3.9 +import info.globalcode.sql.dk.formatting.FakeSqlArray;
    3.10  import info.globalcode.sql.dk.formatting.Formatter;
    3.11  import info.globalcode.sql.dk.formatting.FormatterContext;
    3.12  import info.globalcode.sql.dk.formatting.FormatterException;
    3.13  import java.io.BufferedReader;
    3.14  import java.io.InputStreamReader;
    3.15  import java.io.PrintStream;
    3.16 +import java.sql.Array;
    3.17  import java.sql.Driver;
    3.18 +import java.sql.DriverPropertyInfo;
    3.19  import java.sql.SQLException;
    3.20  import java.util.ArrayList;
    3.21  import java.util.EnumSet;
    3.22 +import java.util.HashSet;
    3.23  import java.util.List;
    3.24  import java.util.ServiceLoader;
    3.25 +import java.util.Set;
    3.26  import java.util.logging.Level;
    3.27  import java.util.logging.Logger;
    3.28  import javax.sql.rowset.RowSetMetaDataImpl;
    3.29 @@ -47,6 +53,10 @@
    3.30  public class InfoLister {
    3.31  
    3.32  	private static final Logger log = Logger.getLogger(InfoLister.class.getName());
    3.33 +	/**
    3.34 +	 * Fake database name for output formatting
    3.35 +	 */
    3.36 +	public static final String CONFIG_DB_NAME = "sqldk_configuration";
    3.37  	private PrintStream out;
    3.38  	private ConfigurationProvider configurationProvider;
    3.39  	private CLIOptions options;
    3.40 @@ -67,6 +77,7 @@
    3.41  			switch (infoType) {
    3.42  				case CONNECTION:
    3.43  				case JDBC_DRIVERS:
    3.44 +				case JDBC_PROPERTIES:
    3.45  				case DATABASES:
    3.46  				case FORMATTERS:
    3.47  				case TYPES:
    3.48 @@ -79,10 +90,10 @@
    3.49  			try (Formatter f = getFormatter()) {
    3.50  				formatter = f;
    3.51  				formatter.writeStartBatch();
    3.52 -				formatter.writeStartDatabase(new DatabaseDefinition());
    3.53 -				formatter.writeStartStatement();
    3.54 +				DatabaseDefinition dd = new DatabaseDefinition();
    3.55 +				dd.setName(CONFIG_DB_NAME);
    3.56 +				formatter.writeStartDatabase(dd);
    3.57  				showInfos(commands);
    3.58 -				formatter.writeEndStatement();
    3.59  				formatter.writeEndDatabase();
    3.60  				formatter.writeEndBatch();
    3.61  				formatter.close();
    3.62 @@ -117,7 +128,7 @@
    3.63  			data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName()});
    3.64  		}
    3.65  
    3.66 -		printTable(formatter, header, data);
    3.67 +		printTable(formatter, header, data, "-- configured and built-in output formatters", null);
    3.68  
    3.69  
    3.70  	}
    3.71 @@ -128,7 +139,7 @@
    3.72  		for (SQLType sqlType : SQLType.values()) {
    3.73  			data.add(new Object[]{sqlType.name(), sqlType.getCode()});
    3.74  		}
    3.75 -		printTable(formatter, header, data);
    3.76 +		printTable(formatter, header, data, "-- data types", null);
    3.77  		log.log(Level.INFO, "Type names in --types option are case insensitive");
    3.78  	}
    3.79  
    3.80 @@ -148,7 +159,7 @@
    3.81  			}
    3.82  		}
    3.83  
    3.84 -		printTable(formatter, header, data);
    3.85 +		printTable(formatter, header, data, "-- configured databases", null);
    3.86  	}
    3.87  
    3.88  	public void listJdbcDrivers() throws FormatterException, ConfigurationException {
    3.89 @@ -167,11 +178,90 @@
    3.90  				d.getMajorVersion() + "." + d.getMinorVersion(),
    3.91  				d.getMajorVersion(),
    3.92  				d.getMinorVersion(),
    3.93 -				d.jdbcCompliant()});
    3.94 +				d.jdbcCompliant()
    3.95 +			});
    3.96  		}
    3.97  
    3.98 -		printTable(formatter, header, data);
    3.99 +		printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null);
   3.100 +	}
   3.101  
   3.102 +	public void listJdbcProperties() throws FormatterException, ConfigurationException {
   3.103 +		for (String dbName : options.getDatabaseNamesToListProperties()) {
   3.104 +			ColumnsHeader header = constructHeader(
   3.105 +					new HeaderField("property_name", SQLType.VARCHAR),
   3.106 +					new HeaderField("required", SQLType.BOOLEAN),
   3.107 +					new HeaderField("choices", SQLType.ARRAY),
   3.108 +					new HeaderField("configured_value", SQLType.VARCHAR),
   3.109 +					new HeaderField("description", SQLType.VARCHAR));
   3.110 +			List<Object[]> data = new ArrayList<>();
   3.111 +
   3.112 +			DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
   3.113 +
   3.114 +			Driver driver = findDriver(dd);
   3.115 +
   3.116 +			if (driver == null) {
   3.117 +				log.log(Level.WARNING, "No JDBC driver was found for DB: {0} with URL: {1}", new Object[]{dd.getName(), dd.getUrl()});
   3.118 +			} else {
   3.119 +				log.log(Level.INFO, "For DB: {0} was found JDBC driver: {1}", new Object[]{dd.getName(), driver.getClass().getName()});
   3.120 +
   3.121 +				try {
   3.122 +					DriverPropertyInfo[] propertyInfos = driver.getPropertyInfo(dd.getUrl(), dd.getProperties().getJavaProperties());
   3.123 +
   3.124 +					Set<String> standardProperties = new HashSet<>();
   3.125 +
   3.126 +					for (DriverPropertyInfo pi : propertyInfos) {
   3.127 +						Array choices = new FakeSqlArray(pi.choices, SQLType.VARCHAR);
   3.128 +						data.add(new Object[]{
   3.129 +							pi.name,
   3.130 +							pi.required,
   3.131 +							choices.getArray() == null ? "" : choices,
   3.132 +							pi.value == null ? "" : pi.value,
   3.133 +							pi.description
   3.134 +						});
   3.135 +						standardProperties.add(pi.name);
   3.136 +					}
   3.137 +
   3.138 +					for (Property p : dd.getProperties()) {
   3.139 +						if (!standardProperties.contains(p.getName())) {
   3.140 +							data.add(new Object[]{
   3.141 +								p.getName(),
   3.142 +								"",
   3.143 +								"",
   3.144 +								p.getValue(),
   3.145 +								""
   3.146 +							});
   3.147 +							log.log(Level.WARNING, "Your configuration contains property „{0}“ not declared by the JDBC driver.", p.getName());
   3.148 +						}
   3.149 +					}
   3.150 +
   3.151 +				} catch (SQLException e) {
   3.152 +					log.log(Level.WARNING, "Error during getting property infos.", e);
   3.153 +				}
   3.154 +
   3.155 +				List<Parameter> parameters = new ArrayList<>();
   3.156 +				parameters.add(new NamedParameter("databgase", dbName, SQLType.VARCHAR));
   3.157 +				parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
   3.158 +				parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
   3.159 +				parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
   3.160 +
   3.161 +				printTable(formatter, header, data, "-- configured and configurable JDBC driver properties", parameters);
   3.162 +			}
   3.163 +		}
   3.164 +
   3.165 +	}
   3.166 +
   3.167 +	private Driver findDriver(DatabaseDefinition dd) {
   3.168 +		final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
   3.169 +		for (Driver d : drivers) {
   3.170 +			try {
   3.171 +				if (d.acceptsURL(dd.getUrl())) {
   3.172 +					return d;
   3.173 +				}
   3.174 +			} catch (SQLException e) {
   3.175 +				log.log(Level.WARNING, "Error during finding JDBC driver for: " + dd.getName(), e);
   3.176 +			}
   3.177 +		}
   3.178 +		return null;
   3.179  	}
   3.180  
   3.181  	public void testConnection() throws FormatterException, ConfigurationException {
   3.182 @@ -185,7 +275,7 @@
   3.183  			data.add(testConnection(dbName));
   3.184  		}
   3.185  
   3.186 -		printTable(formatter, header, data);
   3.187 +		printTable(formatter, header, data, "-- database configuration and connectivity test", null);
   3.188  	}
   3.189  
   3.190  	public Object[] testConnection(String dbName) {
   3.191 @@ -228,7 +318,16 @@
   3.192  		out.println(line);
   3.193  	}
   3.194  
   3.195 -	private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data) throws ConfigurationException, FormatterException {
   3.196 +	private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data, String sql, List<Parameter> parameters) throws ConfigurationException, FormatterException {
   3.197 +		formatter.writeStartStatement();
   3.198 +
   3.199 +		if (sql != null) {
   3.200 +			formatter.writeQuery(sql);
   3.201 +			if (parameters != null) {
   3.202 +				formatter.writeParameters(parameters);
   3.203 +			}
   3.204 +		}
   3.205 +
   3.206  		formatter.writeStartResultSet(header);
   3.207  
   3.208  		for (Object[] row : data) {
   3.209 @@ -240,6 +339,7 @@
   3.210  		}
   3.211  
   3.212  		formatter.writeEndResultSet();
   3.213 +		formatter.writeEndStatement();
   3.214  	}
   3.215  
   3.216  	private Formatter getFormatter() throws ConfigurationException, FormatterException {
   3.217 @@ -319,6 +419,12 @@
   3.218  				infoLister.listJdbcDrivers();
   3.219  			}
   3.220  		},
   3.221 +		JDBC_PROPERTIES {
   3.222 +			@Override
   3.223 +			public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   3.224 +				infoLister.listJdbcProperties();
   3.225 +			}
   3.226 +		},
   3.227  		DATABASES {
   3.228  			@Override
   3.229  			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/formatting/FakeSqlArray.java	Wed Jan 15 21:06:12 2014 +0100
     4.3 @@ -0,0 +1,96 @@
     4.4 +/**
     4.5 + * SQL-DK
     4.6 + * Copyright © 2014 František Kučera (frantovo.cz)
     4.7 + *
     4.8 + * This program is free software: you can redistribute it and/or modify
     4.9 + * it under the terms of the GNU General Public License as published by
    4.10 + * the Free Software Foundation, either version 3 of the License, or
    4.11 + * (at your option) any later version.
    4.12 + *
    4.13 + * This program is distributed in the hope that it will be useful,
    4.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    4.16 + * GNU General Public License for more details.
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License
    4.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    4.20 + */
    4.21 +package info.globalcode.sql.dk.formatting;
    4.22 +
    4.23 +import info.globalcode.sql.dk.SQLType;
    4.24 +import java.sql.Array;
    4.25 +import java.sql.ResultSet;
    4.26 +import java.sql.SQLException;
    4.27 +import java.util.Map;
    4.28 +
    4.29 +/**
    4.30 + * Fake SQL array, for formatting purposes only
    4.31 + *
    4.32 + * @author Ing. František Kučera (frantovo.cz)
    4.33 + */
    4.34 +public class FakeSqlArray implements Array {
    4.35 +
    4.36 +	private static final UnsupportedOperationException exception = new UnsupportedOperationException("This is just a fake SQL array.");
    4.37 +	private final Object[] data;
    4.38 +	private final SQLType baseType;
    4.39 +
    4.40 +	public FakeSqlArray(Object[] data, SQLType baseType) {
    4.41 +		this.data = data;
    4.42 +		this.baseType = baseType;
    4.43 +	}
    4.44 +
    4.45 +	@Override
    4.46 +	public String getBaseTypeName() throws SQLException {
    4.47 +		return baseType.name();
    4.48 +	}
    4.49 +
    4.50 +	@Override
    4.51 +	public int getBaseType() throws SQLException {
    4.52 +		return baseType.getCode();
    4.53 +	}
    4.54 +
    4.55 +	@Override
    4.56 +	public Object getArray() throws SQLException {
    4.57 +		return data;
    4.58 +	}
    4.59 +
    4.60 +	@Override
    4.61 +	public Object getArray(Map<String, Class<?>> map) throws SQLException {
    4.62 +		throw exception;
    4.63 +	}
    4.64 +
    4.65 +	@Override
    4.66 +	public Object getArray(long index, int count) throws SQLException {
    4.67 +		throw exception;
    4.68 +	}
    4.69 +
    4.70 +	@Override
    4.71 +	public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
    4.72 +		throw exception;
    4.73 +	}
    4.74 +
    4.75 +	@Override
    4.76 +	public ResultSet getResultSet() throws SQLException {
    4.77 +		throw exception;
    4.78 +	}
    4.79 +
    4.80 +	@Override
    4.81 +	public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
    4.82 +		throw exception;
    4.83 +	}
    4.84 +
    4.85 +	@Override
    4.86 +	public ResultSet getResultSet(long index, int count) throws SQLException {
    4.87 +		throw exception;
    4.88 +	}
    4.89 +
    4.90 +	@Override
    4.91 +	public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map) throws SQLException {
    4.92 +		throw exception;
    4.93 +	}
    4.94 +
    4.95 +	@Override
    4.96 +	public void free() throws SQLException {
    4.97 +		throw exception;
    4.98 +	}
    4.99 +}
     5.1 --- a/scripts/bash_completion.pl	Wed Jan 15 18:15:55 2014 +0100
     5.2 +++ b/scripts/bash_completion.pl	Wed Jan 15 21:06:12 2014 +0100
     5.3 @@ -50,7 +50,7 @@
     5.4  	prev=${COMP_WORDS[COMP_CWORD-1]}
     5.5  
     5.6  	case "$prev" in
     5.7 -	--db | --test-connection)
     5.8 +	--db | --test-connection | --list-jdbc-properties)
     5.9  		if [ -f '.$databasesFile.' ]; then
    5.10  			COMPREPLY=( $( compgen -W " $( cat '.$databasesFile.' ) " -- $cur ) )
    5.11  			return 0