# HG changeset patch # User František Kučera # Date 1431815276 -7200 # Node ID a32bfcbdee51b6289711c28e694480a33f877733 # Parent 862d0a8747ac0ce5877a63df8874e2f9a4cd4a45 jdbc-dk-driver: first working version diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/conf/META-INF/services/java.sql.Driver --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/jdbc-dk-driver/conf/META-INF/services/java.sql.Driver Sun May 17 00:27:56 2015 +0200 @@ -0,0 +1,1 @@ +info.globalcode.sql.dk.jdbc.Driver diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/nbproject/build-impl.xml --- a/java/jdbc-dk-driver/nbproject/build-impl.xml Sat May 16 23:58:06 2015 +0200 +++ b/java/jdbc-dk-driver/nbproject/build-impl.xml Sun May 17 00:27:56 2015 +0200 @@ -127,6 +127,7 @@ + @@ -224,6 +225,7 @@ + Must set src.conf.dir Must set src.dir Must set src.sql-dk.dir Must set test.src.dir @@ -247,7 +249,7 @@ - + @@ -288,7 +290,7 @@ - + @@ -321,7 +323,7 @@ - + @@ -919,11 +921,12 @@ - + + @@ -946,7 +949,7 @@ Must select some files in the IDE or set javac.includes - + @@ -1212,6 +1215,9 @@ + + + @@ -1225,6 +1231,9 @@ + + + diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/nbproject/genfiles.properties --- a/java/jdbc-dk-driver/nbproject/genfiles.properties Sat May 16 23:58:06 2015 +0200 +++ b/java/jdbc-dk-driver/nbproject/genfiles.properties Sun May 17 00:27:56 2015 +0200 @@ -1,8 +1,8 @@ -build.xml.data.CRC32=64e20838 +build.xml.data.CRC32=50d83c90 build.xml.script.CRC32=3b53b17c build.xml.stylesheet.CRC32=8064a381@1.75.2.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=64e20838 -nbproject/build-impl.xml.script.CRC32=01f7bc2f +nbproject/build-impl.xml.data.CRC32=50d83c90 +nbproject/build-impl.xml.script.CRC32=0d479eb1 nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/nbproject/project.properties --- a/java/jdbc-dk-driver/nbproject/project.properties Sat May 16 23:58:06 2015 +0200 +++ b/java/jdbc-dk-driver/nbproject/project.properties Sun May 17 00:27:56 2015 +0200 @@ -37,8 +37,8 @@ javac.deprecation=false javac.processorpath=\ ${javac.classpath} -javac.source=1.8 -javac.target=1.8 +javac.source=1.7 +javac.target=1.7 javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir} @@ -69,6 +69,7 @@ ${javac.test.classpath}:\ ${build.test.classes.dir} source.encoding=UTF-8 +src.conf.dir=conf src.dir=src src.sql-dk.dir=libs/sql-dk test.src.dir=test diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/nbproject/project.xml --- a/java/jdbc-dk-driver/nbproject/project.xml Sat May 16 23:58:06 2015 +0200 +++ b/java/jdbc-dk-driver/nbproject/project.xml Sun May 17 00:27:56 2015 +0200 @@ -5,6 +5,7 @@ jdbc-dk-driver + diff -r 862d0a8747ac -r a32bfcbdee51 java/jdbc-dk-driver/src/info/globalcode/sql/dk/jdbc/Driver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/java/jdbc-dk-driver/src/info/globalcode/sql/dk/jdbc/Driver.java Sun May 17 00:27:56 2015 +0200 @@ -0,0 +1,156 @@ +/** + * SQL-DK + * Copyright © 2015 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.jdbc; + +import info.globalcode.sql.dk.Constants; +import info.globalcode.sql.dk.configuration.Configuration; +import info.globalcode.sql.dk.configuration.ConfigurationException; +import info.globalcode.sql.dk.configuration.DatabaseDefinition; +import info.globalcode.sql.dk.configuration.Loader; +import info.globalcode.sql.dk.configuration.Properties; +import info.globalcode.sql.dk.configuration.Property; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + *

+ * Meta JDBC driver that works as redirector/router. It loads SQL-DK's configuration file and + * instantiates a real JDBC connection (PostgreSQL, MariDB etc.) of given name. + *

+ * + *

+ * Raison d'être: user can define his/her database connections just once (in SQL-DK's configuration) + * and use them in many other programs – there is no need to define the connection (hostname, + * username, password, properties…) in each application again and again. User will simply connect to + * e.g. jdbc:sql-dk://my-connection and this driver reads parameters of + * my-connection from SQL-DK's configuration and returns real driver implementation. + *

+ * + *

+ * Of course, the real JDBC driver for given database is still needed on the class path. + *

+ * + *

+ * TODO: current version is quite heavy-weight, because it includes whole SQL-DK source tree. Some + * refactoring and separation is desired to provide more light-weight JDBC driver. Although the + * public interface and behavior of this driver should remain same. + *

+ * + * @author Ing. František Kučera (frantovo.cz) + */ +public class Driver implements java.sql.Driver { + + private static final Logger log = Logger.getLogger(Driver.class.getName()); + + private final Loader loader = new Loader(); + + static { + try { + DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + log.log(Level.SEVERE, "Unable to register JDBC driver", e); + } + } + + @Override + public Connection connect(String url, java.util.Properties info) throws SQLException { + if (acceptsURL(url)) { + log.log(Level.FINER, "Loading SQL-DK configuration for URL: {0}", url); + String name = extractDatabaseName(url); + log.log(Level.FINE, "Loading SQL-DK configuration for name: {0}", name); + + try { + return getConnection(name, info); + } catch (ConfigurationException e) { + log.log(Level.SEVERE, "Unable to load SQL-DK configuration for name: {0}. Is it defined in {1}?", new Object[]{name, Constants.CONFIG_FILE}); + throw new SQLException("Unable to load SQL-DK configuration for name: " + name, e); + } + } else { + throw new SQLException("Unsupported URL: " + url); + } + } + + private Connection getConnection(String connectionName, java.util.Properties info) throws SQLException, ConfigurationException { + Configuration c = loader.loadConfiguration(); + DatabaseDefinition dd = c.getDatabase(connectionName); + + if (acceptsURL(dd.getUrl())) { + log.log(Level.SEVERE, "SQL-DK meta JDBC driver loops to itself: {0} → {1} Please check {2}", new Object[]{connectionName, dd.getUrl(), Constants.CONFIG_FILE}); + throw new ConfigurationException("SQL-DK meta JDBC driver loops to itself."); + } else { + return Loader.jdbcConnect(dd, translate(info)); + } + } + + private String extractDatabaseName(String url) { + return url.split("//", 2)[1]; + } + + /** + * TODO: refactor/move, reuse + * + * @param info + * @return + */ + private Properties translate(java.util.Properties info) { + Properties properties = new Properties(); + + for (String name : info.stringPropertyNames()) { + String value = info.getProperty(name); + properties.add(new Property(name, value)); + } + + return properties; + } + + @Override + public boolean acceptsURL(String url) throws SQLException { + return url != null && url.startsWith("jdbc:sql-dk://"); + } + + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException { + return new DriverPropertyInfo[0]; + } + + @Override + public int getMajorVersion() { + return 0; + } + + @Override + public int getMinorVersion() { + return 1; + } + + @Override + public boolean jdbcCompliant() { + return false; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException("Not supported yet."); + } + +} diff -r 862d0a8747ac -r a32bfcbdee51 java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java --- a/java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java Sat May 16 23:58:06 2015 +0200 +++ b/java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java Sun May 17 00:27:56 2015 +0200 @@ -22,14 +22,13 @@ import info.globalcode.sql.dk.batch.Batch; import info.globalcode.sql.dk.batch.BatchException; import info.globalcode.sql.dk.configuration.DatabaseDefinition; +import info.globalcode.sql.dk.configuration.Loader; import info.globalcode.sql.dk.configuration.Properties; -import info.globalcode.sql.dk.configuration.Property; import info.globalcode.sql.dk.formatting.ColumnsHeader; import info.globalcode.sql.dk.formatting.Formatter; import info.globalcode.sql.dk.jmx.ConnectionManagement; import info.globalcode.sql.dk.jmx.ConnectionManagement.COUNTER; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -49,7 +48,7 @@ public class DatabaseConnection implements AutoCloseable { private static final Logger log = Logger.getLogger(DatabaseConnection.class.getName()); - private static final String JDBC_PROPERTY_USER = "user"; + public static final String JDBC_PROPERTY_USER = "user"; public static final String JDBC_PROPERTY_PASSWORD = "password"; private final DatabaseDefinition databaseDefinition; private final Connection connection; @@ -71,19 +70,7 @@ this.databaseDefinition = databaseDefinition; this.properties = properties; this.connectionMBean = connectionMBean; - - if (properties.hasProperty(JDBC_PROPERTY_PASSWORD)) { - log.log(Level.WARNING, "Passing DB password as CLI parameter is insecure!"); - } - - Properties credentials = new Properties(); - credentials.add(new Property(JDBC_PROPERTY_USER, databaseDefinition.getUserName())); - credentials.add(new Property(JDBC_PROPERTY_PASSWORD, databaseDefinition.getPassword())); - credentials.setDefaults(databaseDefinition.getProperties()); - properties.setDefaults(credentials); - java.util.Properties javaProperties = properties.getJavaProperties(); - - connection = DriverManager.getConnection(databaseDefinition.getUrl(), javaProperties); + this.connection = Loader.jdbcConnect(databaseDefinition, properties); } public void executeQuery(SQLCommand sqlCommand, Formatter formatter) throws SQLException { @@ -116,7 +103,7 @@ private void processCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException { incrementCounter(connectionMBean, COUNTER.COMMAND); resetCounter(connectionMBean, COUNTER.RECORD_CURRENT); - + try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) { log.log(Level.FINE, "Statement prepared"); sqlCommand.parametrize(ps); @@ -157,7 +144,7 @@ while (rs.next()) { incrementCounter(connectionMBean, COUNTER.RECORD_CURRENT); incrementCounter(connectionMBean, COUNTER.RECORD_TOTAL); - + formatter.writeStartRow(); for (int i = 1; i <= columnCount; i++) { diff -r 862d0a8747ac -r a32bfcbdee51 java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Sat May 16 23:58:06 2015 +0200 +++ b/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Sun May 17 00:27:56 2015 +0200 @@ -18,6 +18,13 @@ package info.globalcode.sql.dk.configuration; import info.globalcode.sql.dk.*; +import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_USER; +import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_PASSWORD; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; @@ -28,6 +35,8 @@ */ public class Loader { + private static final Logger log = Logger.getLogger(Loader.class.getName()); + public Configuration loadConfiguration() throws ConfigurationException { try { JAXBContext jaxb = JAXBContext.newInstance(Configuration.class); @@ -38,4 +47,26 @@ } } + /** + * JDBC connection should not be used directly in SQL-DK. + * + * @see DatabaseDefinition#connect(info.globalcode.sql.dk.configuration.Properties) + * @param properties + * @param databaseDefinition + * @return + * @throws java.sql.SQLException + */ + public static Connection jdbcConnect(DatabaseDefinition databaseDefinition, Properties properties) throws SQLException { + if (properties.hasProperty(JDBC_PROPERTY_PASSWORD)) { + log.log(Level.WARNING, "Passing DB password as CLI parameter is insecure!"); + } + Properties credentials = new Properties(); + credentials.add(new Property(JDBC_PROPERTY_USER, databaseDefinition.getUserName())); + credentials.add(new Property(JDBC_PROPERTY_PASSWORD, databaseDefinition.getPassword())); + credentials.setDefaults(databaseDefinition.getProperties()); + properties.setDefaults(credentials); + java.util.Properties javaProperties = properties.getJavaProperties(); + return DriverManager.getConnection(databaseDefinition.getUrl(), javaProperties); + } + }