--- /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
--- 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 @@
</condition>
<condition property="have.sources">
<or>
+ <available file="${src.conf.dir}"/>
<available file="${src.dir}"/>
<available file="${src.sql-dk.dir}"/>
</or>
@@ -224,6 +225,7 @@
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+ <fail unless="src.conf.dir">Must set src.conf.dir</fail>
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="src.sql-dk.dir">Must set src.sql-dk.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
@@ -247,7 +249,7 @@
</target>
<target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
- <attribute default="${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
+ <attribute default="${src.conf.dir}:${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${javac.processorpath}" name="processorpath"/>
@@ -288,7 +290,7 @@
</target>
<target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
- <attribute default="${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
+ <attribute default="${src.conf.dir}:${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${javac.processorpath}" name="processorpath"/>
@@ -321,7 +323,7 @@
</target>
<target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
- <attribute default="${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
+ <attribute default="${src.conf.dir}:${src.dir}:${src.sql-dk.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
@@ -919,11 +921,12 @@
<include name="*"/>
</dirset>
</pathconvert>
- <j2seproject3:depend srcdir="${src.dir}:${src.sql-dk.dir}:${build.generated.subdirs}"/>
+ <j2seproject3:depend srcdir="${src.conf.dir}:${src.dir}:${src.sql-dk.dir}:${build.generated.subdirs}"/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
<copy todir="${build.classes.dir}">
+ <fileset dir="${src.conf.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
<fileset dir="${src.sql-dk.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
@@ -946,7 +949,7 @@
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
- <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}:${src.sql-dk.dir}"/>
+ <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.conf.dir}:${src.dir}:${src.sql-dk.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
@@ -1212,6 +1215,9 @@
<classpath>
<path path="${javac.classpath}"/>
</classpath>
+ <fileset dir="${src.conf.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+ <filename name="**/*.java"/>
+ </fileset>
<fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
@@ -1225,6 +1231,9 @@
<arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
</javadoc>
<copy todir="${dist.javadoc.dir}">
+ <fileset dir="${src.conf.dir}" excludes="${excludes}" includes="${includes}">
+ <filename name="**/doc-files/**"/>
+ </fileset>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/doc-files/**"/>
</fileset>
--- 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
--- 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
--- 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 @@
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>jdbc-dk-driver</name>
<source-roots>
+ <root id="src.conf.dir" name="Config"/>
<root id="src.dir"/>
<root id="src.sql-dk.dir"/>
</source-roots>
--- /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 <http://www.gnu.org/licenses/>.
+ */
+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;
+
+/**
+ * <p>
+ * 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.
+ * </p>
+ *
+ * <p>
+ * 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. <code>jdbc:sql-dk://my-connection</code> and this driver reads parameters of
+ * <code>my-connection</code> from SQL-DK's configuration and returns real driver implementation.
+ * </p>
+ *
+ * <p>
+ * Of course, the real JDBC driver for given database is still needed on the class path.
+ * </p>
+ *
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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.");
+ }
+
+}
--- 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++) {
--- 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);
+ }
+
}