1.1 --- a/.hgignore Mon Mar 04 17:06:42 2019 +0100
1.2 +++ b/.hgignore Mon Mar 04 20:15:24 2019 +0100
1.3 @@ -3,8 +3,8 @@
1.4 *~
1.5 temp/*
1.6
1.7 -java/sql-dk/data/info/globalcode/sql/dk/version.txt
1.8 -java/sql-dk/data/info/globalcode/sql/dk/help.txt
1.9 +java/sql-dk/src/main/resources/info/globalcode/sql/dk/version.txt
1.10 +java/sql-dk/src/main/resources/info/globalcode/sql/dk/help.txt
1.11
1.12 syntax: regexp
1.13
2.1 --- a/distributions/debian/build.sh Mon Mar 04 17:06:42 2019 +0100
2.2 +++ b/distributions/debian/build.sh Mon Mar 04 20:15:24 2019 +0100
2.3 @@ -29,12 +29,12 @@
2.4 cp ../../../xml/config.xsd config.xsd &&
2.5 cp ../../../xml/config.rnc config.rnc &&
2.6 cp ../../../xml/config.xsl config.xsl &&
2.7 -cp ../../../java/sql-dk/dist/sql-dk.jar sql-dk.jar &&
2.8 +cp ../../../java/sql-dk/target/sql-dk-*.jar sql-dk.jar &&
2.9 cp ../../../java/jdbc-loopback-driver/target/jdbc-loopback-driver-*.jar jdbc-loopback-driver.jar &&
2.10 -cp ../../../java/sql-dk/dist/bash-completion.sh SQL-DK && # TODO: should be sql-dk – name conflict with sql-dk in /usr/bin/ (equivs bug)
2.11 +cp ../../../java/sql-dk/target/bash-completion.sh SQL-DK && # TODO: should be sql-dk – name conflict with sql-dk in /usr/bin/ (equivs bug)
2.12
2.13 chmod 755 sql-dk &&
2.14 -chmod 755 SQL-DK &&
2.15 +chmod 644 SQL-DK &&
2.16
2.17 EMAIL=`echo c3FsLWRrLmRlYmlhbkBwdWIuZnJhbnRvdm8uY3oK | base64 -d` &&
2.18 NAME="Ing. František Kučera <$EMAIL>" &&
3.1 --- a/distributions/fedora/sql-dk.spec Mon Mar 04 17:06:42 2019 +0100
3.2 +++ b/distributions/fedora/sql-dk.spec Mon Mar 04 20:15:24 2019 +0100
3.3 @@ -71,9 +71,9 @@
3.4 cp ../../../../xml/config.xsd ${RPM_BUILD_ROOT}/usr/share/doc/sql-dk/
3.5 cp ../../../../xml/config.rnc ${RPM_BUILD_ROOT}/usr/share/doc/sql-dk/
3.6 cp ../../../../xml/config.xsl ${RPM_BUILD_ROOT}/usr/share/doc/sql-dk/
3.7 -cp ../../../../java/sql-dk/dist/sql-dk.jar ${RPM_BUILD_ROOT}/usr/share/sql-dk/
3.8 -cp ../../../../java/jdbc-loopback-driver/dist/jdbc-loopback-driver.jar ${RPM_BUILD_ROOT}/usr/share/sql-dk/
3.9 -cp ../../../../java/sql-dk/dist/bash-completion.sh ${RPM_BUILD_ROOT}/etc/bash_completion.d/sql-dk
3.10 +cp ../../../../java/sql-dk/target/sql-dk-*.jar ${RPM_BUILD_ROOT}/usr/share/sql-dk/
3.11 +cp ../../../../java/jdbc-loopback-driver/target/jdbc-loopback-driver-*.jar ${RPM_BUILD_ROOT}/usr/share/sql-dk/
3.12 +cp ../../../../java/sql-dk/target/bash-completion.sh ${RPM_BUILD_ROOT}/etc/bash_completion.d/sql-dk
3.13
3.14 %files
3.15 %defattr(-,root,root)
3.16 @@ -81,4 +81,3 @@
3.17 /usr/share/sql-dk/*
3.18 /usr/share/doc/sql-dk/*
3.19 /etc/bash_completion.d/*
3.20 -
4.1 --- a/java/sql-dk/bash-completion.sh Mon Mar 04 17:06:42 2019 +0100
4.2 +++ b/java/sql-dk/bash-completion.sh Mon Mar 04 20:15:24 2019 +0100
4.3 @@ -1,8 +1,8 @@
4.4 #!/bin/bash
4.5
4.6 cat \
4.7 - src/info/globalcode/sql/dk/Constants.java \
4.8 - src/info/globalcode/sql/dk/formatting/* \
4.9 - src/info/globalcode/sql/dk/CLIParser.java \
4.10 + src/main/java/info/globalcode/sql/dk/Constants.java \
4.11 + src/main/java/info/globalcode/sql/dk/formatting/* \
4.12 + src/main/java/info/globalcode/sql/dk/CLIParser.java \
4.13 | ../../scripts/bash_completion.pl
4.14
5.1 --- a/java/sql-dk/build.xml Mon Mar 04 17:06:42 2019 +0100
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,102 +0,0 @@
5.4 -<?xml version="1.0" encoding="UTF-8"?>
5.5 -<!--
5.6 - SQL-DK
5.7 - Copyright © 2013 František Kučera (frantovo.cz)
5.8 -
5.9 - This program is free software: you can redistribute it and/or modify
5.10 - it under the terms of the GNU General Public License as published by
5.11 - the Free Software Foundation, either version 3 of the License, or
5.12 - (at your option) any later version.
5.13 -
5.14 - This program is distributed in the hope that it will be useful,
5.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
5.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.17 - GNU General Public License for more details.
5.18 -
5.19 - You should have received a copy of the GNU General Public License
5.20 - along with this program. If not, see <http://www.gnu.org/licenses/>.
5.21 --->
5.22 -
5.23 -<!-- You may freely edit this file. See commented blocks below for -->
5.24 -<!-- some examples of how to customize the build. -->
5.25 -<!-- (If you delete it and reopen the project it will be recreated.) -->
5.26 -<!-- By default, only the Clean and Build commands use this build script. -->
5.27 -<!-- Commands such as Run, Debug, and Test only use this build script if -->
5.28 -<!-- the Compile on Save feature is turned off for the project. -->
5.29 -<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
5.30 -<!-- in the project's Project Properties dialog box.-->
5.31 -<project name="sql-dk" default="default" basedir=".">
5.32 - <description>Builds, tests, and runs the project sql-dk.</description>
5.33 - <import file="nbproject/build-impl.xml"/>
5.34 - <!--
5.35 -
5.36 - There exist several targets which are by default empty and which can be
5.37 - used for execution of your tasks. These targets are usually executed
5.38 - before and after some main targets. They are:
5.39 -
5.40 - -pre-init: called before initialization of project properties
5.41 - -post-init: called after initialization of project properties
5.42 - -pre-compile: called before javac compilation
5.43 - -post-compile: called after javac compilation
5.44 - -pre-compile-single: called before javac compilation of single file
5.45 - -post-compile-single: called after javac compilation of single file
5.46 - -pre-compile-test: called before javac compilation of JUnit tests
5.47 - -post-compile-test: called after javac compilation of JUnit tests
5.48 - -pre-compile-test-single: called before javac compilation of single JUnit test
5.49 - -post-compile-test-single: called after javac compilation of single JUunit test
5.50 - -pre-jar: called before JAR building
5.51 - -post-jar: called after JAR building
5.52 - -post-clean: called after cleaning build products
5.53 -
5.54 - (Targets beginning with '-' are not intended to be called on their own.)
5.55 -
5.56 - Example of inserting an obfuscator after compilation could look like this:
5.57 -
5.58 - <target name="-post-compile">
5.59 - <obfuscate>
5.60 - <fileset dir="${build.classes.dir}"/>
5.61 - </obfuscate>
5.62 - </target>
5.63 -
5.64 - For list of available properties check the imported
5.65 - nbproject/build-impl.xml file.
5.66 -
5.67 -
5.68 - Another way to customize the build is by overriding existing main targets.
5.69 - The targets of interest are:
5.70 -
5.71 - -init-macrodef-javac: defines macro for javac compilation
5.72 - -init-macrodef-junit: defines macro for junit execution
5.73 - -init-macrodef-debug: defines macro for class debugging
5.74 - -init-macrodef-java: defines macro for class execution
5.75 - -do-jar-with-manifest: JAR building (if you are using a manifest)
5.76 - -do-jar-without-manifest: JAR building (if you are not using a manifest)
5.77 - run: execution of project
5.78 - -javadoc-build: Javadoc generation
5.79 - test-report: JUnit report generation
5.80 -
5.81 - An example of overriding the target for project execution could look like this:
5.82 -
5.83 - <target name="run" depends="sql-dk-impl.jar">
5.84 - <exec dir="bin" executable="launcher.exe">
5.85 - <arg file="${dist.jar}"/>
5.86 - </exec>
5.87 - </target>
5.88 -
5.89 - Notice that the overridden target depends on the jar target and not only on
5.90 - the compile target as the regular run target does. Again, for a list of available
5.91 - properties which you can use, check the target you are overriding in the
5.92 - nbproject/build-impl.xml file.
5.93 -
5.94 - -->
5.95 -
5.96 - <target name="-pre-compile">
5.97 - <exec executable="./version-info.sh" output="data/info/globalcode/sql/dk/version.txt"/>
5.98 - <exec executable="./help-generator.sh" output="data/info/globalcode/sql/dk/help.txt"/>
5.99 - </target>
5.100 -
5.101 - <target name="-post-jar">
5.102 - <exec executable="./bash-completion.sh" output="dist/bash-completion.sh"/>
5.103 - </target>
5.104 -
5.105 -</project>
6.1 --- a/java/sql-dk/data/info/globalcode/sql/dk/example-config.xml Mon Mar 04 17:06:42 2019 +0100
6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
6.3 @@ -1,1 +0,0 @@
6.4 -../../../../../../../xml/config.xml
6.5 \ No newline at end of file
7.1 --- a/java/sql-dk/data/info/globalcode/sql/dk/formatter/XhtmlFormatter.css Mon Mar 04 17:06:42 2019 +0100
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,54 +0,0 @@
7.4 -body {
7.5 - font-family: sans-serif;
7.6 - font-size: 16px;
7.7 - padding-left: 16px;
7.8 - padding-right: 16px;
7.9 -}
7.10 -
7.11 -pre {
7.12 - background-color: #ddd;
7.13 - padding: 6px;
7.14 - border-radius: 4px;
7.15 - overflow: auto;
7.16 -
7.17 - -moz-tab-size: 4;
7.18 - -o-tab-size: 4;
7.19 - tab-size: 4;
7.20 -}
7.21 -
7.22 -table {
7.23 - border-collapse:collapse;
7.24 - box-shadow: 3px 3px 3px grey;
7.25 - margin-top: 10px;
7.26 - margin-bottom: 20px;
7.27 -}
7.28 -td, th {
7.29 - border: 1px solid black;
7.30 - padding-top: 4px;
7.31 - padding-bottom: 4px;
7.32 - padding-left: 6px;
7.33 - padding-right: 6px;
7.34 - font-weight: normal;
7.35 -}
7.36 -td.number {
7.37 - text-align: right;
7.38 -}
7.39 -td.boolean {
7.40 - text-align: right;
7.41 -}
7.42 -thead tr {
7.43 - background: #ddd;
7.44 - color:black;
7.45 -}
7.46 -tbody tr:hover {
7.47 - background-color: #eee;
7.48 - color:black;
7.49 -}
7.50 -
7.51 -table ul {
7.52 - margin: 0px;
7.53 -}
7.54 -
7.55 -table li {
7.56 - padding-right: 10px;
7.57 -}
8.1 --- a/java/sql-dk/data/info/globalcode/sql/dk/license.txt Mon Mar 04 17:06:42 2019 +0100
8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
8.3 @@ -1,1 +0,0 @@
8.4 -../../../../../../../license/gpl.txt
8.5 \ No newline at end of file
9.1 --- a/java/sql-dk/help-generator.sh Mon Mar 04 17:06:42 2019 +0100
9.2 +++ b/java/sql-dk/help-generator.sh Mon Mar 04 20:15:24 2019 +0100
9.3 @@ -1,7 +1,7 @@
9.4 #!/bin/bash
9.5
9.6 cat \
9.7 - src/info/globalcode/sql/dk/CLIParser.java \
9.8 - src/info/globalcode/sql/dk/CLIStarter.java \
9.9 + src/main/java/info/globalcode/sql/dk/CLIParser.java \
9.10 + src/main/java/info/globalcode/sql/dk/CLIStarter.java \
9.11 | ../../scripts/help_generator.pl
9.12
10.1 --- a/java/sql-dk/manifest.mf Mon Mar 04 17:06:42 2019 +0100
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,3 +0,0 @@
10.4 -Manifest-Version: 1.0
10.5 -X-COMMENT: Main-Class will be added automatically by build
10.6 -
11.1 --- a/java/sql-dk/nbproject/build-impl.xml Mon Mar 04 17:06:42 2019 +0100
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,1429 +0,0 @@
11.4 -<?xml version="1.0" encoding="UTF-8"?>
11.5 -<!--
11.6 -*** GENERATED FROM project.xml - DO NOT EDIT ***
11.7 -*** EDIT ../build.xml INSTEAD ***
11.8 -
11.9 -For the purpose of easier reading the script
11.10 -is divided into following sections:
11.11 -
11.12 - - initialization
11.13 - - compilation
11.14 - - jar
11.15 - - execution
11.16 - - debugging
11.17 - - javadoc
11.18 - - test compilation
11.19 - - test execution
11.20 - - test debugging
11.21 - - applet
11.22 - - cleanup
11.23 -
11.24 - -->
11.25 -<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="sql-dk-impl">
11.26 - <fail message="Please build using Ant 1.8.0 or higher.">
11.27 - <condition>
11.28 - <not>
11.29 - <antversion atleast="1.8.0"/>
11.30 - </not>
11.31 - </condition>
11.32 - </fail>
11.33 - <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
11.34 - <!--
11.35 - ======================
11.36 - INITIALIZATION SECTION
11.37 - ======================
11.38 - -->
11.39 - <target name="-pre-init">
11.40 - <!-- Empty placeholder for easier customization. -->
11.41 - <!-- You can override this target in the ../build.xml file. -->
11.42 - </target>
11.43 - <target depends="-pre-init" name="-init-private">
11.44 - <property file="nbproject/private/config.properties"/>
11.45 - <property file="nbproject/private/configs/${config}.properties"/>
11.46 - <property file="nbproject/private/private.properties"/>
11.47 - </target>
11.48 - <target depends="-pre-init,-init-private" name="-init-user">
11.49 - <property file="${user.properties.file}"/>
11.50 - <!-- The two properties below are usually overridden -->
11.51 - <!-- by the active platform. Just a fallback. -->
11.52 - <property name="default.javac.source" value="1.6"/>
11.53 - <property name="default.javac.target" value="1.6"/>
11.54 - </target>
11.55 - <target depends="-pre-init,-init-private,-init-user" name="-init-project">
11.56 - <property file="nbproject/configs/${config}.properties"/>
11.57 - <property file="nbproject/project.properties"/>
11.58 - </target>
11.59 - <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
11.60 - <property name="platform.java" value="${java.home}/bin/java"/>
11.61 - <available file="${manifest.file}" property="manifest.available"/>
11.62 - <condition property="splashscreen.available">
11.63 - <and>
11.64 - <not>
11.65 - <equals arg1="${application.splash}" arg2="" trim="true"/>
11.66 - </not>
11.67 - <available file="${application.splash}"/>
11.68 - </and>
11.69 - </condition>
11.70 - <condition property="main.class.available">
11.71 - <and>
11.72 - <isset property="main.class"/>
11.73 - <not>
11.74 - <equals arg1="${main.class}" arg2="" trim="true"/>
11.75 - </not>
11.76 - </and>
11.77 - </condition>
11.78 - <condition property="profile.available">
11.79 - <and>
11.80 - <isset property="javac.profile"/>
11.81 - <length length="0" string="${javac.profile}" when="greater"/>
11.82 - <matches pattern="((1\.[89])|9)(\..*)?" string="${javac.source}"/>
11.83 - </and>
11.84 - </condition>
11.85 - <condition property="do.archive">
11.86 - <or>
11.87 - <not>
11.88 - <istrue value="${jar.archive.disabled}"/>
11.89 - </not>
11.90 - <istrue value="${not.archive.disabled}"/>
11.91 - </or>
11.92 - </condition>
11.93 - <condition property="do.mkdist">
11.94 - <and>
11.95 - <isset property="do.archive"/>
11.96 - <isset property="libs.CopyLibs.classpath"/>
11.97 - <not>
11.98 - <istrue value="${mkdist.disabled}"/>
11.99 - </not>
11.100 - </and>
11.101 - </condition>
11.102 - <condition property="do.archive+manifest.available">
11.103 - <and>
11.104 - <isset property="manifest.available"/>
11.105 - <istrue value="${do.archive}"/>
11.106 - </and>
11.107 - </condition>
11.108 - <condition property="do.archive+main.class.available">
11.109 - <and>
11.110 - <isset property="main.class.available"/>
11.111 - <istrue value="${do.archive}"/>
11.112 - </and>
11.113 - </condition>
11.114 - <condition property="do.archive+splashscreen.available">
11.115 - <and>
11.116 - <isset property="splashscreen.available"/>
11.117 - <istrue value="${do.archive}"/>
11.118 - </and>
11.119 - </condition>
11.120 - <condition property="do.archive+profile.available">
11.121 - <and>
11.122 - <isset property="profile.available"/>
11.123 - <istrue value="${do.archive}"/>
11.124 - </and>
11.125 - </condition>
11.126 - <condition property="have.tests">
11.127 - <or>
11.128 - <available file="${test.src.dir}"/>
11.129 - </or>
11.130 - </condition>
11.131 - <condition property="have.sources">
11.132 - <or>
11.133 - <available file="${src.dir}"/>
11.134 - <available file="${src.data.dir}"/>
11.135 - </or>
11.136 - </condition>
11.137 - <condition property="netbeans.home+have.tests">
11.138 - <and>
11.139 - <isset property="netbeans.home"/>
11.140 - <isset property="have.tests"/>
11.141 - </and>
11.142 - </condition>
11.143 - <condition property="no.javadoc.preview">
11.144 - <and>
11.145 - <isset property="javadoc.preview"/>
11.146 - <isfalse value="${javadoc.preview}"/>
11.147 - </and>
11.148 - </condition>
11.149 - <property name="run.jvmargs" value=""/>
11.150 - <property name="run.jvmargs.ide" value=""/>
11.151 - <property name="javac.compilerargs" value=""/>
11.152 - <property name="work.dir" value="${basedir}"/>
11.153 - <condition property="no.deps">
11.154 - <and>
11.155 - <istrue value="${no.dependencies}"/>
11.156 - </and>
11.157 - </condition>
11.158 - <property name="javac.debug" value="true"/>
11.159 - <property name="javadoc.preview" value="true"/>
11.160 - <property name="application.args" value=""/>
11.161 - <property name="source.encoding" value="${file.encoding}"/>
11.162 - <property name="runtime.encoding" value="${source.encoding}"/>
11.163 - <property name="manifest.encoding" value="${source.encoding}"/>
11.164 - <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
11.165 - <and>
11.166 - <isset property="javadoc.encoding"/>
11.167 - <not>
11.168 - <equals arg1="${javadoc.encoding}" arg2=""/>
11.169 - </not>
11.170 - </and>
11.171 - </condition>
11.172 - <property name="javadoc.encoding.used" value="${source.encoding}"/>
11.173 - <property name="includes" value="**"/>
11.174 - <property name="excludes" value=""/>
11.175 - <property name="do.depend" value="false"/>
11.176 - <condition property="do.depend.true">
11.177 - <istrue value="${do.depend}"/>
11.178 - </condition>
11.179 - <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
11.180 - <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
11.181 - <and>
11.182 - <isset property="endorsed.classpath"/>
11.183 - <not>
11.184 - <equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
11.185 - </not>
11.186 - </and>
11.187 - </condition>
11.188 - <condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
11.189 - <isset property="profile.available"/>
11.190 - </condition>
11.191 - <condition else="false" property="jdkBug6558476">
11.192 - <and>
11.193 - <matches pattern="1\.[56]" string="${java.specification.version}"/>
11.194 - <not>
11.195 - <os family="unix"/>
11.196 - </not>
11.197 - </and>
11.198 - </condition>
11.199 - <condition else="false" property="javac.fork">
11.200 - <or>
11.201 - <istrue value="${jdkBug6558476}"/>
11.202 - <istrue value="${javac.external.vm}"/>
11.203 - </or>
11.204 - </condition>
11.205 - <property name="jar.index" value="false"/>
11.206 - <property name="jar.index.metainf" value="${jar.index}"/>
11.207 - <property name="copylibs.rebase" value="true"/>
11.208 - <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
11.209 - <condition property="junit.available">
11.210 - <or>
11.211 - <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
11.212 - <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
11.213 - </or>
11.214 - </condition>
11.215 - <condition property="testng.available">
11.216 - <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
11.217 - </condition>
11.218 - <condition property="junit+testng.available">
11.219 - <and>
11.220 - <istrue value="${junit.available}"/>
11.221 - <istrue value="${testng.available}"/>
11.222 - </and>
11.223 - </condition>
11.224 - <condition else="testng" property="testng.mode" value="mixed">
11.225 - <istrue value="${junit+testng.available}"/>
11.226 - </condition>
11.227 - <condition else="" property="testng.debug.mode" value="-mixed">
11.228 - <istrue value="${junit+testng.available}"/>
11.229 - </condition>
11.230 - <property name="java.failonerror" value="true"/>
11.231 - </target>
11.232 - <target name="-post-init">
11.233 - <!-- Empty placeholder for easier customization. -->
11.234 - <!-- You can override this target in the ../build.xml file. -->
11.235 - </target>
11.236 - <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
11.237 - <fail unless="src.dir">Must set src.dir</fail>
11.238 - <fail unless="src.data.dir">Must set src.data.dir</fail>
11.239 - <fail unless="test.src.dir">Must set test.src.dir</fail>
11.240 - <fail unless="build.dir">Must set build.dir</fail>
11.241 - <fail unless="dist.dir">Must set dist.dir</fail>
11.242 - <fail unless="build.classes.dir">Must set build.classes.dir</fail>
11.243 - <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
11.244 - <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
11.245 - <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
11.246 - <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
11.247 - <fail unless="dist.jar">Must set dist.jar</fail>
11.248 - </target>
11.249 - <target name="-init-macrodef-property">
11.250 - <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
11.251 - <attribute name="name"/>
11.252 - <attribute name="value"/>
11.253 - <sequential>
11.254 - <property name="@{name}" value="${@{value}}"/>
11.255 - </sequential>
11.256 - </macrodef>
11.257 - </target>
11.258 - <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
11.259 - <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
11.260 - <attribute default="${src.dir}:${src.data.dir}" name="srcdir"/>
11.261 - <attribute default="${build.classes.dir}" name="destdir"/>
11.262 - <attribute default="${javac.classpath}" name="classpath"/>
11.263 - <attribute default="${javac.processorpath}" name="processorpath"/>
11.264 - <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
11.265 - <attribute default="${includes}" name="includes"/>
11.266 - <attribute default="${excludes}" name="excludes"/>
11.267 - <attribute default="${javac.debug}" name="debug"/>
11.268 - <attribute default="${empty.dir}" name="sourcepath"/>
11.269 - <attribute default="${empty.dir}" name="gensrcdir"/>
11.270 - <element name="customize" optional="true"/>
11.271 - <sequential>
11.272 - <property location="${build.dir}/empty" name="empty.dir"/>
11.273 - <mkdir dir="${empty.dir}"/>
11.274 - <mkdir dir="@{apgeneratedsrcdir}"/>
11.275 - <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
11.276 - <src>
11.277 - <dirset dir="@{gensrcdir}" erroronmissingdir="false">
11.278 - <include name="*"/>
11.279 - </dirset>
11.280 - </src>
11.281 - <classpath>
11.282 - <path path="@{classpath}"/>
11.283 - </classpath>
11.284 - <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
11.285 - <compilerarg line="${javac.profile.cmd.line.arg}"/>
11.286 - <compilerarg line="${javac.compilerargs}"/>
11.287 - <compilerarg value="-processorpath"/>
11.288 - <compilerarg path="@{processorpath}:${empty.dir}"/>
11.289 - <compilerarg line="${ap.processors.internal}"/>
11.290 - <compilerarg line="${annotation.processing.processor.options}"/>
11.291 - <compilerarg value="-s"/>
11.292 - <compilerarg path="@{apgeneratedsrcdir}"/>
11.293 - <compilerarg line="${ap.proc.none.internal}"/>
11.294 - <customize/>
11.295 - </javac>
11.296 - </sequential>
11.297 - </macrodef>
11.298 - </target>
11.299 - <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
11.300 - <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
11.301 - <attribute default="${src.dir}:${src.data.dir}" name="srcdir"/>
11.302 - <attribute default="${build.classes.dir}" name="destdir"/>
11.303 - <attribute default="${javac.classpath}" name="classpath"/>
11.304 - <attribute default="${javac.processorpath}" name="processorpath"/>
11.305 - <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
11.306 - <attribute default="${includes}" name="includes"/>
11.307 - <attribute default="${excludes}" name="excludes"/>
11.308 - <attribute default="${javac.debug}" name="debug"/>
11.309 - <attribute default="${empty.dir}" name="sourcepath"/>
11.310 - <attribute default="${empty.dir}" name="gensrcdir"/>
11.311 - <element name="customize" optional="true"/>
11.312 - <sequential>
11.313 - <property location="${build.dir}/empty" name="empty.dir"/>
11.314 - <mkdir dir="${empty.dir}"/>
11.315 - <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
11.316 - <src>
11.317 - <dirset dir="@{gensrcdir}" erroronmissingdir="false">
11.318 - <include name="*"/>
11.319 - </dirset>
11.320 - </src>
11.321 - <classpath>
11.322 - <path path="@{classpath}"/>
11.323 - </classpath>
11.324 - <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
11.325 - <compilerarg line="${javac.profile.cmd.line.arg}"/>
11.326 - <compilerarg line="${javac.compilerargs}"/>
11.327 - <customize/>
11.328 - </javac>
11.329 - </sequential>
11.330 - </macrodef>
11.331 - </target>
11.332 - <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
11.333 - <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
11.334 - <attribute default="${src.dir}:${src.data.dir}" name="srcdir"/>
11.335 - <attribute default="${build.classes.dir}" name="destdir"/>
11.336 - <attribute default="${javac.classpath}" name="classpath"/>
11.337 - <sequential>
11.338 - <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
11.339 - <classpath>
11.340 - <path path="@{classpath}"/>
11.341 - </classpath>
11.342 - </depend>
11.343 - </sequential>
11.344 - </macrodef>
11.345 - <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
11.346 - <attribute default="${build.classes.dir}" name="destdir"/>
11.347 - <sequential>
11.348 - <fail unless="javac.includes">Must set javac.includes</fail>
11.349 - <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
11.350 - <path>
11.351 - <filelist dir="@{destdir}" files="${javac.includes}"/>
11.352 - </path>
11.353 - <globmapper from="*.java" to="*.class"/>
11.354 - </pathconvert>
11.355 - <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
11.356 - <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
11.357 - <delete>
11.358 - <files includesfile="${javac.includesfile.binary}"/>
11.359 - </delete>
11.360 - <delete>
11.361 - <fileset file="${javac.includesfile.binary}"/>
11.362 - </delete>
11.363 - </sequential>
11.364 - </macrodef>
11.365 - </target>
11.366 - <target if="${junit.available}" name="-init-macrodef-junit-init">
11.367 - <condition else="false" property="nb.junit.batch" value="true">
11.368 - <and>
11.369 - <istrue value="${junit.available}"/>
11.370 - <not>
11.371 - <isset property="test.method"/>
11.372 - </not>
11.373 - </and>
11.374 - </condition>
11.375 - <condition else="false" property="nb.junit.single" value="true">
11.376 - <and>
11.377 - <istrue value="${junit.available}"/>
11.378 - <isset property="test.method"/>
11.379 - </and>
11.380 - </condition>
11.381 - </target>
11.382 - <target name="-init-test-properties">
11.383 - <property name="test.binaryincludes" value="<nothing>"/>
11.384 - <property name="test.binarytestincludes" value=""/>
11.385 - <property name="test.binaryexcludes" value=""/>
11.386 - </target>
11.387 - <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
11.388 - <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
11.389 - <attribute default="${includes}" name="includes"/>
11.390 - <attribute default="${excludes}" name="excludes"/>
11.391 - <attribute default="**" name="testincludes"/>
11.392 - <attribute default="" name="testmethods"/>
11.393 - <element name="customize" optional="true"/>
11.394 - <sequential>
11.395 - <property name="junit.forkmode" value="perTest"/>
11.396 - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
11.397 - <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
11.398 - <syspropertyset>
11.399 - <propertyref prefix="test-sys-prop."/>
11.400 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.401 - </syspropertyset>
11.402 - <formatter type="brief" usefile="false"/>
11.403 - <formatter type="xml"/>
11.404 - <jvmarg value="-ea"/>
11.405 - <customize/>
11.406 - </junit>
11.407 - </sequential>
11.408 - </macrodef>
11.409 - </target>
11.410 - <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
11.411 - <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
11.412 - <attribute default="${includes}" name="includes"/>
11.413 - <attribute default="${excludes}" name="excludes"/>
11.414 - <attribute default="**" name="testincludes"/>
11.415 - <attribute default="" name="testmethods"/>
11.416 - <element name="customize" optional="true"/>
11.417 - <sequential>
11.418 - <property name="junit.forkmode" value="perTest"/>
11.419 - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
11.420 - <batchtest todir="${build.test.results.dir}">
11.421 - <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
11.422 - <filename name="@{testincludes}"/>
11.423 - </fileset>
11.424 - <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
11.425 - <filename name="${test.binarytestincludes}"/>
11.426 - </fileset>
11.427 - </batchtest>
11.428 - <syspropertyset>
11.429 - <propertyref prefix="test-sys-prop."/>
11.430 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.431 - </syspropertyset>
11.432 - <formatter type="brief" usefile="false"/>
11.433 - <formatter type="xml"/>
11.434 - <jvmarg value="-ea"/>
11.435 - <customize/>
11.436 - </junit>
11.437 - </sequential>
11.438 - </macrodef>
11.439 - </target>
11.440 - <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
11.441 - <target if="${testng.available}" name="-init-macrodef-testng">
11.442 - <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
11.443 - <attribute default="${includes}" name="includes"/>
11.444 - <attribute default="${excludes}" name="excludes"/>
11.445 - <attribute default="**" name="testincludes"/>
11.446 - <attribute default="" name="testmethods"/>
11.447 - <element name="customize" optional="true"/>
11.448 - <sequential>
11.449 - <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
11.450 - <isset property="test.method"/>
11.451 - </condition>
11.452 - <union id="test.set">
11.453 - <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
11.454 - <filename name="@{testincludes}"/>
11.455 - </fileset>
11.456 - </union>
11.457 - <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
11.458 - <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="sql-dk" testname="TestNG tests" workingDir="${work.dir}">
11.459 - <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
11.460 - <propertyset>
11.461 - <propertyref prefix="test-sys-prop."/>
11.462 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.463 - </propertyset>
11.464 - <customize/>
11.465 - </testng>
11.466 - </sequential>
11.467 - </macrodef>
11.468 - </target>
11.469 - <target name="-init-macrodef-test-impl">
11.470 - <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
11.471 - <attribute default="${includes}" name="includes"/>
11.472 - <attribute default="${excludes}" name="excludes"/>
11.473 - <attribute default="**" name="testincludes"/>
11.474 - <attribute default="" name="testmethods"/>
11.475 - <element implicit="true" name="customize" optional="true"/>
11.476 - <sequential>
11.477 - <echo>No tests executed.</echo>
11.478 - </sequential>
11.479 - </macrodef>
11.480 - </target>
11.481 - <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
11.482 - <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
11.483 - <attribute default="${includes}" name="includes"/>
11.484 - <attribute default="${excludes}" name="excludes"/>
11.485 - <attribute default="**" name="testincludes"/>
11.486 - <attribute default="" name="testmethods"/>
11.487 - <element implicit="true" name="customize" optional="true"/>
11.488 - <sequential>
11.489 - <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
11.490 - <customize/>
11.491 - </j2seproject3:junit>
11.492 - </sequential>
11.493 - </macrodef>
11.494 - </target>
11.495 - <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
11.496 - <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
11.497 - <attribute default="${includes}" name="includes"/>
11.498 - <attribute default="${excludes}" name="excludes"/>
11.499 - <attribute default="**" name="testincludes"/>
11.500 - <attribute default="" name="testmethods"/>
11.501 - <element implicit="true" name="customize" optional="true"/>
11.502 - <sequential>
11.503 - <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
11.504 - <customize/>
11.505 - </j2seproject3:testng>
11.506 - </sequential>
11.507 - </macrodef>
11.508 - </target>
11.509 - <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
11.510 - <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
11.511 - <attribute default="${includes}" name="includes"/>
11.512 - <attribute default="${excludes}" name="excludes"/>
11.513 - <attribute default="**" name="testincludes"/>
11.514 - <attribute default="" name="testmethods"/>
11.515 - <sequential>
11.516 - <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
11.517 - <customize>
11.518 - <classpath>
11.519 - <path path="${run.test.classpath}"/>
11.520 - </classpath>
11.521 - <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
11.522 - <jvmarg line="${run.jvmargs}"/>
11.523 - <jvmarg line="${run.jvmargs.ide}"/>
11.524 - </customize>
11.525 - </j2seproject3:test-impl>
11.526 - </sequential>
11.527 - </macrodef>
11.528 - </target>
11.529 - <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
11.530 - <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.531 - <attribute default="${includes}" name="includes"/>
11.532 - <attribute default="${excludes}" name="excludes"/>
11.533 - <attribute default="**" name="testincludes"/>
11.534 - <attribute default="" name="testmethods"/>
11.535 - <element name="customize" optional="true"/>
11.536 - <sequential>
11.537 - <property name="junit.forkmode" value="perTest"/>
11.538 - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
11.539 - <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
11.540 - <syspropertyset>
11.541 - <propertyref prefix="test-sys-prop."/>
11.542 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.543 - </syspropertyset>
11.544 - <formatter type="brief" usefile="false"/>
11.545 - <formatter type="xml"/>
11.546 - <jvmarg value="-ea"/>
11.547 - <jvmarg line="${debug-args-line}"/>
11.548 - <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
11.549 - <customize/>
11.550 - </junit>
11.551 - </sequential>
11.552 - </macrodef>
11.553 - </target>
11.554 - <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
11.555 - <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.556 - <attribute default="${includes}" name="includes"/>
11.557 - <attribute default="${excludes}" name="excludes"/>
11.558 - <attribute default="**" name="testincludes"/>
11.559 - <attribute default="" name="testmethods"/>
11.560 - <element name="customize" optional="true"/>
11.561 - <sequential>
11.562 - <property name="junit.forkmode" value="perTest"/>
11.563 - <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
11.564 - <batchtest todir="${build.test.results.dir}">
11.565 - <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
11.566 - <filename name="@{testincludes}"/>
11.567 - </fileset>
11.568 - <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
11.569 - <filename name="${test.binarytestincludes}"/>
11.570 - </fileset>
11.571 - </batchtest>
11.572 - <syspropertyset>
11.573 - <propertyref prefix="test-sys-prop."/>
11.574 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.575 - </syspropertyset>
11.576 - <formatter type="brief" usefile="false"/>
11.577 - <formatter type="xml"/>
11.578 - <jvmarg value="-ea"/>
11.579 - <jvmarg line="${debug-args-line}"/>
11.580 - <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
11.581 - <customize/>
11.582 - </junit>
11.583 - </sequential>
11.584 - </macrodef>
11.585 - </target>
11.586 - <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
11.587 - <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
11.588 - <attribute default="${includes}" name="includes"/>
11.589 - <attribute default="${excludes}" name="excludes"/>
11.590 - <attribute default="**" name="testincludes"/>
11.591 - <attribute default="" name="testmethods"/>
11.592 - <element implicit="true" name="customize" optional="true"/>
11.593 - <sequential>
11.594 - <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
11.595 - <customize/>
11.596 - </j2seproject3:junit-debug>
11.597 - </sequential>
11.598 - </macrodef>
11.599 - </target>
11.600 - <target if="${testng.available}" name="-init-macrodef-testng-debug">
11.601 - <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.602 - <attribute default="${main.class}" name="testClass"/>
11.603 - <attribute default="" name="testMethod"/>
11.604 - <element name="customize2" optional="true"/>
11.605 - <sequential>
11.606 - <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
11.607 - <isset property="test.method"/>
11.608 - </condition>
11.609 - <condition else="-suitename sql-dk -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
11.610 - <matches pattern=".*\.xml" string="@{testClass}"/>
11.611 - </condition>
11.612 - <delete dir="${build.test.results.dir}" quiet="true"/>
11.613 - <mkdir dir="${build.test.results.dir}"/>
11.614 - <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
11.615 - <customize>
11.616 - <customize2/>
11.617 - <jvmarg value="-ea"/>
11.618 - <arg line="${testng.debug.mode}"/>
11.619 - <arg line="-d ${build.test.results.dir}"/>
11.620 - <arg line="-listener org.testng.reporters.VerboseReporter"/>
11.621 - <arg line="${testng.cmd.args}"/>
11.622 - </customize>
11.623 - </j2seproject3:debug>
11.624 - </sequential>
11.625 - </macrodef>
11.626 - </target>
11.627 - <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
11.628 - <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
11.629 - <attribute default="${main.class}" name="testClass"/>
11.630 - <attribute default="" name="testMethod"/>
11.631 - <element implicit="true" name="customize2" optional="true"/>
11.632 - <sequential>
11.633 - <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
11.634 - <customize2/>
11.635 - </j2seproject3:testng-debug>
11.636 - </sequential>
11.637 - </macrodef>
11.638 - </target>
11.639 - <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
11.640 - <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.641 - <attribute default="${includes}" name="includes"/>
11.642 - <attribute default="${excludes}" name="excludes"/>
11.643 - <attribute default="**" name="testincludes"/>
11.644 - <attribute default="" name="testmethods"/>
11.645 - <attribute default="${main.class}" name="testClass"/>
11.646 - <attribute default="" name="testMethod"/>
11.647 - <sequential>
11.648 - <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
11.649 - <customize>
11.650 - <classpath>
11.651 - <path path="${run.test.classpath}"/>
11.652 - </classpath>
11.653 - <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
11.654 - <jvmarg line="${run.jvmargs}"/>
11.655 - <jvmarg line="${run.jvmargs.ide}"/>
11.656 - </customize>
11.657 - </j2seproject3:test-debug-impl>
11.658 - </sequential>
11.659 - </macrodef>
11.660 - </target>
11.661 - <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
11.662 - <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.663 - <attribute default="${includes}" name="includes"/>
11.664 - <attribute default="${excludes}" name="excludes"/>
11.665 - <attribute default="**" name="testincludes"/>
11.666 - <attribute default="" name="testmethods"/>
11.667 - <attribute default="${main.class}" name="testClass"/>
11.668 - <attribute default="" name="testMethod"/>
11.669 - <sequential>
11.670 - <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
11.671 - <customize2>
11.672 - <syspropertyset>
11.673 - <propertyref prefix="test-sys-prop."/>
11.674 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.675 - </syspropertyset>
11.676 - </customize2>
11.677 - </j2seproject3:testng-debug-impl>
11.678 - </sequential>
11.679 - </macrodef>
11.680 - </target>
11.681 - <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
11.682 - <!--
11.683 - pre NB7.2 profiling section; consider it deprecated
11.684 - -->
11.685 - <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
11.686 - <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
11.687 - <!-- Empty placeholder for easier customization. -->
11.688 - <!-- You can override this target in the ../build.xml file. -->
11.689 - </target>
11.690 - <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
11.691 - <!-- Empty placeholder for easier customization. -->
11.692 - <!-- You can override this target in the ../build.xml file. -->
11.693 - </target>
11.694 - <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
11.695 - <macrodef name="resolve">
11.696 - <attribute name="name"/>
11.697 - <attribute name="value"/>
11.698 - <sequential>
11.699 - <property name="@{name}" value="${env.@{value}}"/>
11.700 - </sequential>
11.701 - </macrodef>
11.702 - <macrodef name="profile">
11.703 - <attribute default="${main.class}" name="classname"/>
11.704 - <element name="customize" optional="true"/>
11.705 - <sequential>
11.706 - <property environment="env"/>
11.707 - <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
11.708 - <java classname="@{classname}" dir="${profiler.info.dir}" failonerror="${java.failonerror}" fork="true" jvm="${profiler.info.jvm}">
11.709 - <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
11.710 - <jvmarg value="${profiler.info.jvmargs.agent}"/>
11.711 - <jvmarg line="${profiler.info.jvmargs}"/>
11.712 - <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
11.713 - <arg line="${application.args}"/>
11.714 - <classpath>
11.715 - <path path="${run.classpath}"/>
11.716 - </classpath>
11.717 - <syspropertyset>
11.718 - <propertyref prefix="run-sys-prop."/>
11.719 - <mapper from="run-sys-prop.*" to="*" type="glob"/>
11.720 - </syspropertyset>
11.721 - <customize/>
11.722 - </java>
11.723 - </sequential>
11.724 - </macrodef>
11.725 - </target>
11.726 - <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
11.727 - <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
11.728 - <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
11.729 - </target>
11.730 - <!--
11.731 - end of pre NB7.2 profiling section
11.732 - -->
11.733 - <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
11.734 - <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
11.735 - <attribute default="${main.class}" name="name"/>
11.736 - <attribute default="${debug.classpath}" name="classpath"/>
11.737 - <attribute default="" name="stopclassname"/>
11.738 - <sequential>
11.739 - <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
11.740 - <classpath>
11.741 - <path path="@{classpath}"/>
11.742 - </classpath>
11.743 - </nbjpdastart>
11.744 - </sequential>
11.745 - </macrodef>
11.746 - <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
11.747 - <attribute default="${build.classes.dir}" name="dir"/>
11.748 - <sequential>
11.749 - <nbjpdareload>
11.750 - <fileset dir="@{dir}" includes="${fix.classes}">
11.751 - <include name="${fix.includes}*.class"/>
11.752 - </fileset>
11.753 - </nbjpdareload>
11.754 - </sequential>
11.755 - </macrodef>
11.756 - </target>
11.757 - <target name="-init-debug-args">
11.758 - <property name="version-output" value="java version "${ant.java.version}"/>
11.759 - <condition property="have-jdk-older-than-1.4">
11.760 - <or>
11.761 - <contains string="${version-output}" substring="java version "1.0"/>
11.762 - <contains string="${version-output}" substring="java version "1.1"/>
11.763 - <contains string="${version-output}" substring="java version "1.2"/>
11.764 - <contains string="${version-output}" substring="java version "1.3"/>
11.765 - </or>
11.766 - </condition>
11.767 - <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
11.768 - <istrue value="${have-jdk-older-than-1.4}"/>
11.769 - </condition>
11.770 - <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
11.771 - <os family="windows"/>
11.772 - </condition>
11.773 - <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
11.774 - <isset property="debug.transport"/>
11.775 - </condition>
11.776 - </target>
11.777 - <target depends="-init-debug-args" name="-init-macrodef-debug">
11.778 - <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
11.779 - <attribute default="${main.class}" name="classname"/>
11.780 - <attribute default="${debug.classpath}" name="classpath"/>
11.781 - <element name="customize" optional="true"/>
11.782 - <sequential>
11.783 - <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true">
11.784 - <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
11.785 - <jvmarg line="${debug-args-line}"/>
11.786 - <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
11.787 - <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
11.788 - <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
11.789 - <jvmarg line="${run.jvmargs}"/>
11.790 - <jvmarg line="${run.jvmargs.ide}"/>
11.791 - <classpath>
11.792 - <path path="@{classpath}"/>
11.793 - </classpath>
11.794 - <syspropertyset>
11.795 - <propertyref prefix="run-sys-prop."/>
11.796 - <mapper from="run-sys-prop.*" to="*" type="glob"/>
11.797 - </syspropertyset>
11.798 - <customize/>
11.799 - </java>
11.800 - </sequential>
11.801 - </macrodef>
11.802 - </target>
11.803 - <target name="-init-macrodef-java">
11.804 - <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
11.805 - <attribute default="${main.class}" name="classname"/>
11.806 - <attribute default="${run.classpath}" name="classpath"/>
11.807 - <attribute default="jvm" name="jvm"/>
11.808 - <element name="customize" optional="true"/>
11.809 - <sequential>
11.810 - <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true">
11.811 - <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
11.812 - <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
11.813 - <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
11.814 - <jvmarg line="${run.jvmargs}"/>
11.815 - <jvmarg line="${run.jvmargs.ide}"/>
11.816 - <classpath>
11.817 - <path path="@{classpath}"/>
11.818 - </classpath>
11.819 - <syspropertyset>
11.820 - <propertyref prefix="run-sys-prop."/>
11.821 - <mapper from="run-sys-prop.*" to="*" type="glob"/>
11.822 - </syspropertyset>
11.823 - <customize/>
11.824 - </java>
11.825 - </sequential>
11.826 - </macrodef>
11.827 - </target>
11.828 - <target name="-init-macrodef-copylibs">
11.829 - <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
11.830 - <attribute default="${manifest.file}" name="manifest"/>
11.831 - <element name="customize" optional="true"/>
11.832 - <sequential>
11.833 - <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
11.834 - <pathconvert property="run.classpath.without.build.classes.dir">
11.835 - <path path="${run.classpath}"/>
11.836 - <map from="${build.classes.dir.resolved}" to=""/>
11.837 - </pathconvert>
11.838 - <pathconvert pathsep=" " property="jar.classpath">
11.839 - <path path="${run.classpath.without.build.classes.dir}"/>
11.840 - <chainedmapper>
11.841 - <flattenmapper/>
11.842 - <filtermapper>
11.843 - <replacestring from=" " to="%20"/>
11.844 - </filtermapper>
11.845 - <globmapper from="*" to="lib/*"/>
11.846 - </chainedmapper>
11.847 - </pathconvert>
11.848 - <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
11.849 - <copylibs compress="${jar.compress}" excludeFromCopy="${copylibs.excludes}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" manifestencoding="UTF-8" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
11.850 - <fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
11.851 - <manifest>
11.852 - <attribute name="Class-Path" value="${jar.classpath}"/>
11.853 - <customize/>
11.854 - </manifest>
11.855 - </copylibs>
11.856 - </sequential>
11.857 - </macrodef>
11.858 - </target>
11.859 - <target name="-init-presetdef-jar">
11.860 - <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
11.861 - <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifestencoding="UTF-8">
11.862 - <j2seproject1:fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
11.863 - </jar>
11.864 - </presetdef>
11.865 - </target>
11.866 - <target name="-init-ap-cmdline-properties">
11.867 - <property name="annotation.processing.enabled" value="true"/>
11.868 - <property name="annotation.processing.processors.list" value=""/>
11.869 - <property name="annotation.processing.processor.options" value=""/>
11.870 - <property name="annotation.processing.run.all.processors" value="true"/>
11.871 - <property name="javac.processorpath" value="${javac.classpath}"/>
11.872 - <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
11.873 - <condition property="ap.supported.internal" value="true">
11.874 - <not>
11.875 - <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
11.876 - </not>
11.877 - </condition>
11.878 - </target>
11.879 - <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
11.880 - <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
11.881 - <isfalse value="${annotation.processing.run.all.processors}"/>
11.882 - </condition>
11.883 - <condition else="" property="ap.proc.none.internal" value="-proc:none">
11.884 - <isfalse value="${annotation.processing.enabled}"/>
11.885 - </condition>
11.886 - </target>
11.887 - <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
11.888 - <property name="ap.cmd.line.internal" value=""/>
11.889 - </target>
11.890 - <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
11.891 - <!--
11.892 - ===================
11.893 - COMPILATION SECTION
11.894 - ===================
11.895 - -->
11.896 - <target name="-deps-jar-init" unless="built-jar.properties">
11.897 - <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
11.898 - <delete file="${built-jar.properties}" quiet="true"/>
11.899 - </target>
11.900 - <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
11.901 - <echo level="warn" message="Cycle detected: sql-dk was already built"/>
11.902 - </target>
11.903 - <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
11.904 - <mkdir dir="${build.dir}"/>
11.905 - <touch file="${built-jar.properties}" verbose="false"/>
11.906 - <property file="${built-jar.properties}" prefix="already.built.jar."/>
11.907 - <antcall target="-warn-already-built-jar"/>
11.908 - <propertyfile file="${built-jar.properties}">
11.909 - <entry key="${basedir}" value=""/>
11.910 - </propertyfile>
11.911 - </target>
11.912 - <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
11.913 - <target depends="init" name="-check-automatic-build">
11.914 - <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
11.915 - </target>
11.916 - <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
11.917 - <antcall target="clean"/>
11.918 - </target>
11.919 - <target depends="init,deps-jar" name="-pre-pre-compile">
11.920 - <mkdir dir="${build.classes.dir}"/>
11.921 - </target>
11.922 - <target name="-pre-compile">
11.923 - <!-- Empty placeholder for easier customization. -->
11.924 - <!-- You can override this target in the ../build.xml file. -->
11.925 - </target>
11.926 - <target if="do.depend.true" name="-compile-depend">
11.927 - <pathconvert property="build.generated.subdirs">
11.928 - <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
11.929 - <include name="*"/>
11.930 - </dirset>
11.931 - </pathconvert>
11.932 - <j2seproject3:depend srcdir="${src.dir}:${src.data.dir}:${build.generated.subdirs}"/>
11.933 - </target>
11.934 - <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
11.935 - <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
11.936 - <copy todir="${build.classes.dir}">
11.937 - <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
11.938 - <fileset dir="${src.data.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
11.939 - </copy>
11.940 - </target>
11.941 - <target if="has.persistence.xml" name="-copy-persistence-xml">
11.942 - <mkdir dir="${build.classes.dir}/META-INF"/>
11.943 - <copy todir="${build.classes.dir}/META-INF">
11.944 - <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
11.945 - </copy>
11.946 - </target>
11.947 - <target name="-post-compile">
11.948 - <!-- Empty placeholder for easier customization. -->
11.949 - <!-- You can override this target in the ../build.xml file. -->
11.950 - </target>
11.951 - <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
11.952 - <target name="-pre-compile-single">
11.953 - <!-- Empty placeholder for easier customization. -->
11.954 - <!-- You can override this target in the ../build.xml file. -->
11.955 - </target>
11.956 - <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
11.957 - <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
11.958 - <j2seproject3:force-recompile/>
11.959 - <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}:${src.data.dir}"/>
11.960 - </target>
11.961 - <target name="-post-compile-single">
11.962 - <!-- Empty placeholder for easier customization. -->
11.963 - <!-- You can override this target in the ../build.xml file. -->
11.964 - </target>
11.965 - <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
11.966 - <!--
11.967 - ====================
11.968 - JAR BUILDING SECTION
11.969 - ====================
11.970 - -->
11.971 - <target depends="init" name="-pre-pre-jar">
11.972 - <dirname file="${dist.jar}" property="dist.jar.dir"/>
11.973 - <mkdir dir="${dist.jar.dir}"/>
11.974 - </target>
11.975 - <target name="-pre-jar">
11.976 - <!-- Empty placeholder for easier customization. -->
11.977 - <!-- You can override this target in the ../build.xml file. -->
11.978 - </target>
11.979 - <target depends="init" if="do.archive" name="-do-jar-create-manifest" unless="manifest.available">
11.980 - <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
11.981 - <touch file="${tmp.manifest.file}" verbose="false"/>
11.982 - </target>
11.983 - <target depends="init" if="do.archive+manifest.available" name="-do-jar-copy-manifest">
11.984 - <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
11.985 - <copy encoding="${manifest.encoding}" file="${manifest.file}" outputencoding="UTF-8" tofile="${tmp.manifest.file}"/>
11.986 - </target>
11.987 - <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+main.class.available" name="-do-jar-set-mainclass">
11.988 - <manifest encoding="UTF-8" file="${tmp.manifest.file}" mode="update">
11.989 - <attribute name="Main-Class" value="${main.class}"/>
11.990 - </manifest>
11.991 - </target>
11.992 - <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+profile.available" name="-do-jar-set-profile">
11.993 - <manifest encoding="UTF-8" file="${tmp.manifest.file}" mode="update">
11.994 - <attribute name="Profile" value="${javac.profile}"/>
11.995 - </manifest>
11.996 - </target>
11.997 - <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-set-splashscreen">
11.998 - <basename file="${application.splash}" property="splashscreen.basename"/>
11.999 - <mkdir dir="${build.classes.dir}/META-INF"/>
11.1000 - <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
11.1001 - <manifest encoding="UTF-8" file="${tmp.manifest.file}" mode="update">
11.1002 - <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
11.1003 - </manifest>
11.1004 - </target>
11.1005 - <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.mkdist" name="-do-jar-copylibs">
11.1006 - <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
11.1007 - <echo level="info">To run this application from the command line without Ant, try:</echo>
11.1008 - <property location="${dist.jar}" name="dist.jar.resolved"/>
11.1009 - <echo level="info">java -jar "${dist.jar.resolved}"</echo>
11.1010 - </target>
11.1011 - <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
11.1012 - <j2seproject1:jar manifest="${tmp.manifest.file}"/>
11.1013 - <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
11.1014 - <property location="${dist.jar}" name="dist.jar.resolved"/>
11.1015 - <pathconvert property="run.classpath.with.dist.jar">
11.1016 - <path path="${run.classpath}"/>
11.1017 - <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
11.1018 - </pathconvert>
11.1019 - <condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java} -cp ${run.classpath.with.dist.jar} ${main.class}">
11.1020 - <isset property="main.class.available"/>
11.1021 - </condition>
11.1022 - <condition else="debug" property="jar.usage.level" value="info">
11.1023 - <isset property="main.class.available"/>
11.1024 - </condition>
11.1025 - <echo level="${jar.usage.level}" message="${jar.usage.message}"/>
11.1026 - </target>
11.1027 - <target depends="-do-jar-copylibs" if="do.archive" name="-do-jar-delete-manifest">
11.1028 - <delete>
11.1029 - <fileset file="${tmp.manifest.file}"/>
11.1030 - </delete>
11.1031 - </target>
11.1032 - <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-jar,-do-jar-delete-manifest" name="-do-jar-without-libraries"/>
11.1033 - <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-copylibs,-do-jar-delete-manifest" name="-do-jar-with-libraries"/>
11.1034 - <target name="-post-jar">
11.1035 - <!-- Empty placeholder for easier customization. -->
11.1036 - <!-- You can override this target in the ../build.xml file. -->
11.1037 - </target>
11.1038 - <target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
11.1039 - <target depends="init,compile,-pre-jar,-do-jar,-post-jar" description="Build JAR." name="jar"/>
11.1040 - <!--
11.1041 - =================
11.1042 - EXECUTION SECTION
11.1043 - =================
11.1044 - -->
11.1045 - <target depends="init,compile" description="Run a main class." name="run">
11.1046 - <j2seproject1:java>
11.1047 - <customize>
11.1048 - <arg line="${application.args}"/>
11.1049 - </customize>
11.1050 - </j2seproject1:java>
11.1051 - </target>
11.1052 - <target name="-do-not-recompile">
11.1053 - <property name="javac.includes.binary" value=""/>
11.1054 - </target>
11.1055 - <target depends="init,compile-single" name="run-single">
11.1056 - <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
11.1057 - <j2seproject1:java classname="${run.class}"/>
11.1058 - </target>
11.1059 - <target depends="init,compile-test-single" name="run-test-with-main">
11.1060 - <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
11.1061 - <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
11.1062 - </target>
11.1063 - <!--
11.1064 - =================
11.1065 - DEBUGGING SECTION
11.1066 - =================
11.1067 - -->
11.1068 - <target depends="init" if="netbeans.home" name="-debug-start-debugger">
11.1069 - <j2seproject1:nbjpdastart name="${debug.class}"/>
11.1070 - </target>
11.1071 - <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
11.1072 - <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
11.1073 - </target>
11.1074 - <target depends="init,compile" name="-debug-start-debuggee">
11.1075 - <j2seproject3:debug>
11.1076 - <customize>
11.1077 - <arg line="${application.args}"/>
11.1078 - </customize>
11.1079 - </j2seproject3:debug>
11.1080 - </target>
11.1081 - <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
11.1082 - <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
11.1083 - <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
11.1084 - </target>
11.1085 - <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
11.1086 - <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
11.1087 - <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
11.1088 - <j2seproject3:debug classname="${debug.class}"/>
11.1089 - </target>
11.1090 - <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
11.1091 - <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
11.1092 - <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
11.1093 - <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
11.1094 - </target>
11.1095 - <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
11.1096 - <target depends="init" name="-pre-debug-fix">
11.1097 - <fail unless="fix.includes">Must set fix.includes</fail>
11.1098 - <property name="javac.includes" value="${fix.includes}.java"/>
11.1099 - </target>
11.1100 - <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
11.1101 - <j2seproject1:nbjpdareload/>
11.1102 - </target>
11.1103 - <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
11.1104 - <!--
11.1105 - =================
11.1106 - PROFILING SECTION
11.1107 - =================
11.1108 - -->
11.1109 - <!--
11.1110 - pre NB7.2 profiler integration
11.1111 - -->
11.1112 - <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
11.1113 - <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
11.1114 - <nbprofiledirect>
11.1115 - <classpath>
11.1116 - <path path="${run.classpath}"/>
11.1117 - </classpath>
11.1118 - </nbprofiledirect>
11.1119 - <profile/>
11.1120 - </target>
11.1121 - <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
11.1122 - <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
11.1123 - <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
11.1124 - <nbprofiledirect>
11.1125 - <classpath>
11.1126 - <path path="${run.classpath}"/>
11.1127 - </classpath>
11.1128 - </nbprofiledirect>
11.1129 - <profile classname="${profile.class}"/>
11.1130 - </target>
11.1131 - <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
11.1132 - <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
11.1133 - <nbprofiledirect>
11.1134 - <classpath>
11.1135 - <path path="${run.classpath}"/>
11.1136 - </classpath>
11.1137 - </nbprofiledirect>
11.1138 - <profile classname="sun.applet.AppletViewer">
11.1139 - <customize>
11.1140 - <arg value="${applet.url}"/>
11.1141 - </customize>
11.1142 - </profile>
11.1143 - </target>
11.1144 - <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
11.1145 - <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
11.1146 - <nbprofiledirect>
11.1147 - <classpath>
11.1148 - <path path="${run.test.classpath}"/>
11.1149 - </classpath>
11.1150 - </nbprofiledirect>
11.1151 - <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
11.1152 - <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
11.1153 - <jvmarg value="${profiler.info.jvmargs.agent}"/>
11.1154 - <jvmarg line="${profiler.info.jvmargs}"/>
11.1155 - <test name="${profile.class}"/>
11.1156 - <classpath>
11.1157 - <path path="${run.test.classpath}"/>
11.1158 - </classpath>
11.1159 - <syspropertyset>
11.1160 - <propertyref prefix="test-sys-prop."/>
11.1161 - <mapper from="test-sys-prop.*" to="*" type="glob"/>
11.1162 - </syspropertyset>
11.1163 - <formatter type="brief" usefile="false"/>
11.1164 - <formatter type="xml"/>
11.1165 - </junit>
11.1166 - </target>
11.1167 - <!--
11.1168 - end of pre NB72 profiling section
11.1169 - -->
11.1170 - <target if="netbeans.home" name="-profile-check">
11.1171 - <condition property="profiler.configured">
11.1172 - <or>
11.1173 - <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
11.1174 - <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
11.1175 - </or>
11.1176 - </condition>
11.1177 - </target>
11.1178 - <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
11.1179 - <startprofiler/>
11.1180 - <antcall target="run"/>
11.1181 - </target>
11.1182 - <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
11.1183 - <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
11.1184 - <startprofiler/>
11.1185 - <antcall target="run-single"/>
11.1186 - </target>
11.1187 - <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
11.1188 - <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
11.1189 - <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
11.1190 - <startprofiler/>
11.1191 - <antcall target="test-single"/>
11.1192 - </target>
11.1193 - <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
11.1194 - <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
11.1195 - <startprofiler/>
11.1196 - <antcall target="run-test-with-main"/>
11.1197 - </target>
11.1198 - <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
11.1199 - <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
11.1200 - <startprofiler/>
11.1201 - <antcall target="run-applet"/>
11.1202 - </target>
11.1203 - <!--
11.1204 - ===============
11.1205 - JAVADOC SECTION
11.1206 - ===============
11.1207 - -->
11.1208 - <target depends="init" if="have.sources" name="-javadoc-build">
11.1209 - <mkdir dir="${dist.javadoc.dir}"/>
11.1210 - <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
11.1211 - <and>
11.1212 - <isset property="endorsed.classpath.cmd.line.arg"/>
11.1213 - <not>
11.1214 - <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
11.1215 - </not>
11.1216 - </and>
11.1217 - </condition>
11.1218 - <condition else="" property="bug5101868workaround" value="*.java">
11.1219 - <matches pattern="1\.[56](\..*)?" string="${java.version}"/>
11.1220 - </condition>
11.1221 - <javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
11.1222 - <classpath>
11.1223 - <path path="${javac.classpath}"/>
11.1224 - </classpath>
11.1225 - <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
11.1226 - <filename name="**/*.java"/>
11.1227 - </fileset>
11.1228 - <fileset dir="${src.data.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
11.1229 - <filename name="**/*.java"/>
11.1230 - </fileset>
11.1231 - <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
11.1232 - <include name="**/*.java"/>
11.1233 - <exclude name="*.java"/>
11.1234 - </fileset>
11.1235 - <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
11.1236 - </javadoc>
11.1237 - <copy todir="${dist.javadoc.dir}">
11.1238 - <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
11.1239 - <filename name="**/doc-files/**"/>
11.1240 - </fileset>
11.1241 - <fileset dir="${src.data.dir}" excludes="${excludes}" includes="${includes}">
11.1242 - <filename name="**/doc-files/**"/>
11.1243 - </fileset>
11.1244 - <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
11.1245 - <include name="**/doc-files/**"/>
11.1246 - </fileset>
11.1247 - </copy>
11.1248 - </target>
11.1249 - <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
11.1250 - <nbbrowse file="${dist.javadoc.dir}/index.html"/>
11.1251 - </target>
11.1252 - <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
11.1253 - <!--
11.1254 - =========================
11.1255 - TEST COMPILATION SECTION
11.1256 - =========================
11.1257 - -->
11.1258 - <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
11.1259 - <mkdir dir="${build.test.classes.dir}"/>
11.1260 - </target>
11.1261 - <target name="-pre-compile-test">
11.1262 - <!-- Empty placeholder for easier customization. -->
11.1263 - <!-- You can override this target in the ../build.xml file. -->
11.1264 - </target>
11.1265 - <target if="do.depend.true" name="-compile-test-depend">
11.1266 - <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
11.1267 - </target>
11.1268 - <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
11.1269 - <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
11.1270 - <copy todir="${build.test.classes.dir}">
11.1271 - <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
11.1272 - </copy>
11.1273 - </target>
11.1274 - <target name="-post-compile-test">
11.1275 - <!-- Empty placeholder for easier customization. -->
11.1276 - <!-- You can override this target in the ../build.xml file. -->
11.1277 - </target>
11.1278 - <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
11.1279 - <target name="-pre-compile-test-single">
11.1280 - <!-- Empty placeholder for easier customization. -->
11.1281 - <!-- You can override this target in the ../build.xml file. -->
11.1282 - </target>
11.1283 - <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
11.1284 - <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
11.1285 - <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
11.1286 - <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
11.1287 - <copy todir="${build.test.classes.dir}">
11.1288 - <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
11.1289 - </copy>
11.1290 - </target>
11.1291 - <target name="-post-compile-test-single">
11.1292 - <!-- Empty placeholder for easier customization. -->
11.1293 - <!-- You can override this target in the ../build.xml file. -->
11.1294 - </target>
11.1295 - <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
11.1296 - <!--
11.1297 - =======================
11.1298 - TEST EXECUTION SECTION
11.1299 - =======================
11.1300 - -->
11.1301 - <target depends="init" if="have.tests" name="-pre-test-run">
11.1302 - <mkdir dir="${build.test.results.dir}"/>
11.1303 - </target>
11.1304 - <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
11.1305 - <j2seproject3:test includes="${includes}" testincludes="**/*Test.java"/>
11.1306 - </target>
11.1307 - <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
11.1308 - <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
11.1309 - </target>
11.1310 - <target depends="init" if="have.tests" name="test-report"/>
11.1311 - <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
11.1312 - <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
11.1313 - <target depends="init" if="have.tests" name="-pre-test-run-single">
11.1314 - <mkdir dir="${build.test.results.dir}"/>
11.1315 - </target>
11.1316 - <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
11.1317 - <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
11.1318 - <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
11.1319 - </target>
11.1320 - <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
11.1321 - <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
11.1322 - </target>
11.1323 - <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
11.1324 - <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
11.1325 - <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
11.1326 - <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
11.1327 - <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
11.1328 - </target>
11.1329 - <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
11.1330 - <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
11.1331 - </target>
11.1332 - <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
11.1333 - <!--
11.1334 - =======================
11.1335 - TEST DEBUGGING SECTION
11.1336 - =======================
11.1337 - -->
11.1338 - <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
11.1339 - <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
11.1340 - <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
11.1341 - </target>
11.1342 - <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
11.1343 - <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
11.1344 - <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
11.1345 - <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
11.1346 - </target>
11.1347 - <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
11.1348 - <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
11.1349 - </target>
11.1350 - <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
11.1351 - <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
11.1352 - <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
11.1353 - <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
11.1354 - </target>
11.1355 - <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
11.1356 - <!--
11.1357 - =========================
11.1358 - APPLET EXECUTION SECTION
11.1359 - =========================
11.1360 - -->
11.1361 - <target depends="init,compile-single" name="run-applet">
11.1362 - <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
11.1363 - <j2seproject1:java classname="sun.applet.AppletViewer">
11.1364 - <customize>
11.1365 - <arg value="${applet.url}"/>
11.1366 - </customize>
11.1367 - </j2seproject1:java>
11.1368 - </target>
11.1369 - <!--
11.1370 - =========================
11.1371 - APPLET DEBUGGING SECTION
11.1372 - =========================
11.1373 - -->
11.1374 - <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
11.1375 - <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
11.1376 - <j2seproject3:debug classname="sun.applet.AppletViewer">
11.1377 - <customize>
11.1378 - <arg value="${applet.url}"/>
11.1379 - </customize>
11.1380 - </j2seproject3:debug>
11.1381 - </target>
11.1382 - <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
11.1383 - <!--
11.1384 - ===============
11.1385 - CLEANUP SECTION
11.1386 - ===============
11.1387 - -->
11.1388 - <target name="-deps-clean-init" unless="built-clean.properties">
11.1389 - <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
11.1390 - <delete file="${built-clean.properties}" quiet="true"/>
11.1391 - </target>
11.1392 - <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
11.1393 - <echo level="warn" message="Cycle detected: sql-dk was already built"/>
11.1394 - </target>
11.1395 - <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
11.1396 - <mkdir dir="${build.dir}"/>
11.1397 - <touch file="${built-clean.properties}" verbose="false"/>
11.1398 - <property file="${built-clean.properties}" prefix="already.built.clean."/>
11.1399 - <antcall target="-warn-already-built-clean"/>
11.1400 - <propertyfile file="${built-clean.properties}">
11.1401 - <entry key="${basedir}" value=""/>
11.1402 - </propertyfile>
11.1403 - </target>
11.1404 - <target depends="init" name="-do-clean">
11.1405 - <delete dir="${build.dir}"/>
11.1406 - <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
11.1407 - </target>
11.1408 - <target name="-post-clean">
11.1409 - <!-- Empty placeholder for easier customization. -->
11.1410 - <!-- You can override this target in the ../build.xml file. -->
11.1411 - </target>
11.1412 - <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
11.1413 - <target name="-check-call-dep">
11.1414 - <property file="${call.built.properties}" prefix="already.built."/>
11.1415 - <condition property="should.call.dep">
11.1416 - <and>
11.1417 - <not>
11.1418 - <isset property="already.built.${call.subproject}"/>
11.1419 - </not>
11.1420 - <available file="${call.script}"/>
11.1421 - </and>
11.1422 - </condition>
11.1423 - </target>
11.1424 - <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
11.1425 - <ant antfile="${call.script}" inheritall="false" target="${call.target}">
11.1426 - <propertyset>
11.1427 - <propertyref prefix="transfer."/>
11.1428 - <mapper from="transfer.*" to="*" type="glob"/>
11.1429 - </propertyset>
11.1430 - </ant>
11.1431 - </target>
11.1432 -</project>
12.1 --- a/java/sql-dk/nbproject/genfiles.properties Mon Mar 04 17:06:42 2019 +0100
12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
12.3 @@ -1,8 +0,0 @@
12.4 -build.xml.data.CRC32=b51b939b
12.5 -build.xml.script.CRC32=f55b3340
12.6 -build.xml.stylesheet.CRC32=28e38971@1.56.1.46
12.7 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
12.8 -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
12.9 -nbproject/build-impl.xml.data.CRC32=b51b939b
12.10 -nbproject/build-impl.xml.script.CRC32=6a0815e1
12.11 -nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48
13.1 --- a/java/sql-dk/nbproject/project.properties Mon Mar 04 17:06:42 2019 +0100
13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
13.3 @@ -1,75 +0,0 @@
13.4 -annotation.processing.enabled=true
13.5 -annotation.processing.enabled.in.editor=false
13.6 -annotation.processing.processors.list=
13.7 -annotation.processing.run.all.processors=true
13.8 -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
13.9 -application.title=sql-dk
13.10 -application.vendor=fiki
13.11 -build.classes.dir=${build.dir}/classes
13.12 -build.classes.excludes=**/*.java,**/*.form
13.13 -# This directory is removed when the project is cleaned:
13.14 -build.dir=build
13.15 -build.generated.dir=${build.dir}/generated
13.16 -build.generated.sources.dir=${build.dir}/generated-sources
13.17 -# Only compile against the classpath explicitly listed here:
13.18 -build.sysclasspath=ignore
13.19 -build.test.classes.dir=${build.dir}/test/classes
13.20 -build.test.results.dir=${build.dir}/test/results
13.21 -# Uncomment to specify the preferred debugger connection transport:
13.22 -#debug.transport=dt_socket
13.23 -debug.classpath=\
13.24 - ${run.classpath}
13.25 -debug.test.classpath=\
13.26 - ${run.test.classpath}
13.27 -# This directory is removed when the project is cleaned:
13.28 -dist.dir=dist
13.29 -dist.jar=${dist.dir}/sql-dk.jar
13.30 -dist.javadoc.dir=${dist.dir}/javadoc
13.31 -endorsed.classpath=
13.32 -excludes=
13.33 -includes=**
13.34 -jar.compress=false
13.35 -javac.classpath=
13.36 -# Space-separated list of extra javac options
13.37 -javac.compilerargs=
13.38 -javac.deprecation=false
13.39 -javac.processorpath=\
13.40 - ${javac.classpath}
13.41 -javac.source=1.8
13.42 -javac.target=1.8
13.43 -javac.test.classpath=\
13.44 - ${javac.classpath}:\
13.45 - ${build.classes.dir}:\
13.46 - ${libs.testng.classpath}
13.47 -javac.test.processorpath=\
13.48 - ${javac.test.classpath}
13.49 -javadoc.additionalparam=
13.50 -javadoc.author=false
13.51 -javadoc.encoding=${source.encoding}
13.52 -javadoc.noindex=false
13.53 -javadoc.nonavbar=false
13.54 -javadoc.notree=false
13.55 -javadoc.private=false
13.56 -javadoc.splitindex=true
13.57 -javadoc.use=true
13.58 -javadoc.version=false
13.59 -javadoc.windowtitle=
13.60 -main.class=info.globalcode.sql.dk.CLIStarter
13.61 -manifest.file=manifest.mf
13.62 -meta.inf.dir=${src.dir}/META-INF
13.63 -mkdist.disabled=false
13.64 -platform.active=default_platform
13.65 -run.classpath=\
13.66 - ${javac.classpath}:\
13.67 - ${build.classes.dir}
13.68 -# Space-separated list of JVM arguments used when running the project.
13.69 -# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
13.70 -# To set system properties for unit tests define test-sys-prop.name=value:
13.71 -run.jvmargs=
13.72 -run.test.classpath=\
13.73 - ${javac.test.classpath}:\
13.74 - ${build.test.classes.dir}
13.75 -source.encoding=UTF-8
13.76 -src.data.dir=data
13.77 -src.dir=src
13.78 -test.src.dir=test
14.1 --- a/java/sql-dk/nbproject/project.xml Mon Mar 04 17:06:42 2019 +0100
14.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
14.3 @@ -1,16 +0,0 @@
14.4 -<?xml version="1.0" encoding="UTF-8"?>
14.5 -<project xmlns="http://www.netbeans.org/ns/project/1">
14.6 - <type>org.netbeans.modules.java.j2seproject</type>
14.7 - <configuration>
14.8 - <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
14.9 - <name>sql-dk</name>
14.10 - <source-roots>
14.11 - <root id="src.dir"/>
14.12 - <root id="src.data.dir"/>
14.13 - </source-roots>
14.14 - <test-roots>
14.15 - <root id="test.src.dir"/>
14.16 - </test-roots>
14.17 - </data>
14.18 - </configuration>
14.19 -</project>
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/java/sql-dk/pom.xml Mon Mar 04 20:15:24 2019 +0100
15.3 @@ -0,0 +1,69 @@
15.4 +<?xml version="1.0" encoding="UTF-8"?>
15.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
15.6 + <modelVersion>4.0.0</modelVersion>
15.7 + <groupId>info.globalcode.sql.dk</groupId>
15.8 + <artifactId>sql-dk</artifactId>
15.9 + <version>0.10-SNAPSHOT</version>
15.10 + <packaging>jar</packaging>
15.11 +
15.12 + <dependencies>
15.13 + <dependency>
15.14 + <groupId>org.testng</groupId>
15.15 + <artifactId>testng</artifactId>
15.16 + <version>6.9.9</version>
15.17 + <scope>test</scope>
15.18 + </dependency>
15.19 + </dependencies>
15.20 +
15.21 + <properties>
15.22 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15.23 + <maven.compiler.source>1.8</maven.compiler.source>
15.24 + <maven.compiler.target>1.8</maven.compiler.target>
15.25 + </properties>
15.26 +
15.27 + <build>
15.28 + <plugins>
15.29 + <plugin>
15.30 + <groupId>org.codehaus.mojo</groupId>
15.31 + <artifactId>exec-maven-plugin</artifactId>
15.32 + <version>1.6.0</version>
15.33 + <executions>
15.34 + <execution>
15.35 + <id>version-info</id>
15.36 + <phase>generate-sources</phase>
15.37 + <goals>
15.38 + <goal>exec</goal>
15.39 + </goals>
15.40 + <configuration>
15.41 + <executable>./version-info.sh</executable>
15.42 + <outputFile>src/main/resources/info/globalcode/sql/dk/version.txt</outputFile><!-- TODO: move to target/generated-sources/ -->
15.43 + </configuration>
15.44 + </execution>
15.45 + <execution>
15.46 + <id>help-generator</id>
15.47 + <phase>generate-sources</phase>
15.48 + <goals>
15.49 + <goal>exec</goal>
15.50 + </goals>
15.51 + <configuration>
15.52 + <executable>./help-generator.sh</executable>
15.53 + <outputFile>src/main/resources/info/globalcode/sql/dk/help.txt</outputFile><!-- TODO: move to target/generated-sources/ -->
15.54 + </configuration>
15.55 + </execution>
15.56 + <execution>
15.57 + <id>bash-completion</id>
15.58 + <phase>generate-sources</phase>
15.59 + <goals>
15.60 + <goal>exec</goal>
15.61 + </goals>
15.62 + <configuration>
15.63 + <executable>./bash-completion.sh</executable>
15.64 + <outputFile>target/bash-completion.sh</outputFile>
15.65 + </configuration>
15.66 + </execution>
15.67 + </executions>
15.68 + </plugin>
15.69 + </plugins>
15.70 + </build>
15.71 +
15.72 +</project>
16.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIOptions.java Mon Mar 04 17:06:42 2019 +0100
16.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
16.3 @@ -1,283 +0,0 @@
16.4 -/**
16.5 - * SQL-DK
16.6 - * Copyright © 2013 František Kučera (frantovo.cz)
16.7 - *
16.8 - * This program is free software: you can redistribute it and/or modify
16.9 - * it under the terms of the GNU General Public License as published by
16.10 - * the Free Software Foundation, either version 3 of the License, or
16.11 - * (at your option) any later version.
16.12 - *
16.13 - * This program is distributed in the hope that it will be useful,
16.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
16.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16.16 - * GNU General Public License for more details.
16.17 - *
16.18 - * You should have received a copy of the GNU General Public License
16.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
16.20 - */
16.21 -package info.globalcode.sql.dk;
16.22 -
16.23 -import static info.globalcode.sql.dk.Functions.isNotEmpty;
16.24 -import static info.globalcode.sql.dk.Functions.equalz;
16.25 -import info.globalcode.sql.dk.InfoLister.InfoType;
16.26 -import info.globalcode.sql.dk.configuration.Properties;
16.27 -import info.globalcode.sql.dk.configuration.Property;
16.28 -import java.io.InputStream;
16.29 -import java.io.OutputStream;
16.30 -import java.util.ArrayList;
16.31 -import java.util.Collection;
16.32 -import java.util.EnumSet;
16.33 -import java.util.LinkedHashSet;
16.34 -import java.util.List;
16.35 -import java.util.Set;
16.36 -import java.util.regex.Pattern;
16.37 -import java.util.regex.PatternSyntaxException;
16.38 -
16.39 -/**
16.40 - * Holds options from command line, validates them, combines with configuration and provides derived
16.41 - * objects.
16.42 - *
16.43 - * @author Ing. František Kučera (frantovo.cz)
16.44 - */
16.45 -public class CLIOptions {
16.46 -
16.47 - public static final String DEFAULT_NAME_PREFIX = ":";
16.48 - public static final String DEFAULT_NAME_SUFFIX = "(?=([^\\w]|$))";
16.49 - private String sql;
16.50 - private String databaseName;
16.51 - private final Set<String> databaseNamesToTest = new LinkedHashSet<>();
16.52 - private final Set<String> databaseNamesToListProperties = new LinkedHashSet<>();
16.53 - private final Set<String> formatterNamesToListProperties = new LinkedHashSet<>();
16.54 - private String namePrefix = DEFAULT_NAME_PREFIX;
16.55 - private String nameSuffix = DEFAULT_NAME_SUFFIX;
16.56 - private String formatterName;
16.57 - private boolean batch;
16.58 - private final Properties formatterProperties = new Properties();
16.59 - private final Properties databaseProperties = new Properties();
16.60 -
16.61 - public enum MODE {
16.62 -
16.63 - QUERY_NOW,
16.64 - PREPARE_BATCH,
16.65 - EXECUTE_BATCH,
16.66 - JUST_SHOW_INFO
16.67 - }
16.68 - private final List<NamedParameter> namedParameters = new ArrayList<>();
16.69 - private final List<Parameter> numberedParameters = new ArrayList<>();
16.70 - private final EnumSet<InfoType> showInfo = EnumSet.noneOf(InfoType.class);
16.71 -
16.72 - public void validate() throws InvalidOptionsException {
16.73 - InvalidOptionsException e = new InvalidOptionsException();
16.74 -
16.75 - MODE mode = getMode();
16.76 - if (mode == null) {
16.77 - e.addProblem(new InvalidOptionsException.OptionProblem("Invalid combination of DB, SQL and BATCH – please specify just 2 of this 3 options"));
16.78 - } else if (mode == MODE.JUST_SHOW_INFO) {
16.79 - if (!namedParameters.isEmpty()) {
16.80 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not use named parameters if just showing info."));
16.81 - }
16.82 - if (!numberedParameters.isEmpty()) {
16.83 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not use numbered parameters if just showing info."));
16.84 - }
16.85 - if (isNotEmpty(sql, false)) {
16.86 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify SQL if just showing info."));
16.87 - }
16.88 - if (isNotEmpty(databaseName, false)) {
16.89 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify database if just showing info."));
16.90 - }
16.91 - if (batch) {
16.92 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify batch if just showing info."));
16.93 - }
16.94 - if (!equalz(namePrefix, DEFAULT_NAME_PREFIX)) {
16.95 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name prefix if just showing info."));
16.96 - }
16.97 - if (!equalz(nameSuffix, DEFAULT_NAME_SUFFIX)) {
16.98 - e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name suffix if just showing info."));
16.99 - }
16.100 - if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) {
16.101 - e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested."));
16.102 - }
16.103 - if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) {
16.104 - e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed."));
16.105 - }
16.106 - }
16.107 -
16.108 - if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) {
16.109 - e.addProblem(new InvalidOptionsException.OptionProblem("Named and numbered parameters can not be used together in one command."));
16.110 - }
16.111 -
16.112 - try {
16.113 - Pattern.compile(namePrefix + "test" + nameSuffix);
16.114 - } catch (PatternSyntaxException regexException) {
16.115 - e.addProblem(new InvalidOptionsException.OptionProblem("Ivalid regular expression in name prefix or suffix", regexException));
16.116 - }
16.117 -
16.118 - if (e.hasProblems()) {
16.119 - throw e;
16.120 - }
16.121 - }
16.122 -
16.123 - private boolean hasSql() {
16.124 - return isNotEmpty(getSql(), true);
16.125 - }
16.126 -
16.127 - private boolean hasDb() {
16.128 - return isNotEmpty(getDatabaseName(), true);
16.129 - }
16.130 -
16.131 - /**
16.132 - * Depends on options: DB, BATCH, SQL
16.133 - *
16.134 - * @return mode | or null if options are not yet initialized or combination of options is
16.135 - * invalid
16.136 - */
16.137 - public MODE getMode() {
16.138 - if (hasDb() && !batch && hasSql()) {
16.139 - return MODE.QUERY_NOW;
16.140 - } else if (!hasDb() && batch && hasSql()) {
16.141 - return MODE.PREPARE_BATCH;
16.142 - } else if (hasDb() && batch && !hasSql()) {
16.143 - return MODE.EXECUTE_BATCH;
16.144 - } else {
16.145 - return showInfo.isEmpty() ? null : MODE.JUST_SHOW_INFO;
16.146 - }
16.147 - }
16.148 -
16.149 - public String getSql() {
16.150 - return sql;
16.151 - }
16.152 -
16.153 - public void setSql(String sql) {
16.154 - this.sql = sql;
16.155 - }
16.156 -
16.157 - public String getDatabaseName() {
16.158 - return databaseName;
16.159 - }
16.160 -
16.161 - public void setDatabaseName(String databaseName) {
16.162 - this.databaseName = databaseName;
16.163 - }
16.164 -
16.165 - public void setBatch(boolean batch) {
16.166 - this.batch = batch;
16.167 - }
16.168 -
16.169 - public Collection<NamedParameter> getNamedParameters() {
16.170 - return namedParameters;
16.171 - }
16.172 -
16.173 - public List<Parameter> getNumberedParameters() {
16.174 - return numberedParameters;
16.175 - }
16.176 -
16.177 - public void addNumberedParameter(Parameter p) {
16.178 - numberedParameters.add(p);
16.179 - }
16.180 -
16.181 - public void addNamedParameter(NamedParameter p) {
16.182 - namedParameters.add(p);
16.183 - }
16.184 -
16.185 - public Properties getDatabaseProperties() {
16.186 - return databaseProperties;
16.187 - }
16.188 -
16.189 - public Properties getFormatterProperties() {
16.190 - return formatterProperties;
16.191 - }
16.192 -
16.193 - public void addDatabaseProperty(Property p) {
16.194 - databaseProperties.add(p);
16.195 - }
16.196 -
16.197 - public void addFormatterProperty(Property p) {
16.198 - formatterProperties.add(p);
16.199 - }
16.200 -
16.201 - /**
16.202 - * @return regular expression describing the name prefix
16.203 - */
16.204 - public String getNamePrefix() {
16.205 - return namePrefix;
16.206 - }
16.207 -
16.208 - /**
16.209 - * @param namePrefix
16.210 - * @see #getNamePrefix()
16.211 - */
16.212 - public void setNamePrefix(String namePrefix) {
16.213 - this.namePrefix = namePrefix;
16.214 - }
16.215 -
16.216 - /**
16.217 - * @return regular expression describing the name prefix
16.218 - */
16.219 - public String getNameSuffix() {
16.220 - return nameSuffix;
16.221 - }
16.222 -
16.223 - /**
16.224 - * @param nameSuffix
16.225 - * @see #getNameSuffix()
16.226 - */
16.227 - public void setNameSuffix(String nameSuffix) {
16.228 - this.nameSuffix = nameSuffix;
16.229 - }
16.230 -
16.231 - public String getFormatterName() {
16.232 - return formatterName;
16.233 - }
16.234 -
16.235 - public void setFormatterName(String formatterName) {
16.236 - this.formatterName = formatterName;
16.237 - }
16.238 -
16.239 - public void addShowInfo(InfoType info) {
16.240 - showInfo.add(info);
16.241 - }
16.242 -
16.243 - public EnumSet<InfoType> getShowInfo() {
16.244 - return showInfo;
16.245 - }
16.246 -
16.247 - public Set<String> getDatabaseNamesToTest() {
16.248 - return databaseNamesToTest;
16.249 - }
16.250 -
16.251 - public void addDatabaseNameToTest(String name) {
16.252 - databaseNamesToTest.add(name);
16.253 - }
16.254 -
16.255 - public Set<String> getDatabaseNamesToListProperties() {
16.256 - return databaseNamesToListProperties;
16.257 - }
16.258 -
16.259 - public void addDatabaseNameToListProperties(String name) {
16.260 - databaseNamesToListProperties.add(name);
16.261 - }
16.262 -
16.263 - public Set<String> getFormatterNamesToListProperties() {
16.264 - return formatterNamesToListProperties;
16.265 - }
16.266 -
16.267 - public void addFormatterNameToListProperties(String name) {
16.268 - formatterNamesToListProperties.add(name);
16.269 - }
16.270 -
16.271 - public SQLCommand getSQLCommand() {
16.272 - if (namedParameters.isEmpty()) {
16.273 - return new SQLCommandNumbered(sql, numberedParameters);
16.274 - } else {
16.275 - return new SQLCommandNamed(sql, namedParameters, namePrefix, nameSuffix);
16.276 - }
16.277 - }
16.278 -
16.279 - public OutputStream getOutputStream() {
16.280 - return System.out;
16.281 - }
16.282 -
16.283 - public InputStream getInputStream() {
16.284 - return System.in;
16.285 - }
16.286 -}
17.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java Mon Mar 04 17:06:42 2019 +0100
17.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
17.3 @@ -1,216 +0,0 @@
17.4 -/**
17.5 - * SQL-DK
17.6 - * Copyright © 2013 František Kučera (frantovo.cz)
17.7 - *
17.8 - * This program is free software: you can redistribute it and/or modify
17.9 - * it under the terms of the GNU General Public License as published by
17.10 - * the Free Software Foundation, either version 3 of the License, or
17.11 - * (at your option) any later version.
17.12 - *
17.13 - * This program is distributed in the hope that it will be useful,
17.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
17.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17.16 - * GNU General Public License for more details.
17.17 - *
17.18 - * You should have received a copy of the GNU General Public License
17.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
17.20 - */
17.21 -package info.globalcode.sql.dk;
17.22 -
17.23 -import static info.globalcode.sql.dk.Functions.readString;
17.24 -import info.globalcode.sql.dk.InfoLister.InfoType;
17.25 -import info.globalcode.sql.dk.configuration.Property;
17.26 -import java.io.IOException;
17.27 -import java.io.InputStream;
17.28 -import java.util.ArrayList;
17.29 -import java.util.HashMap;
17.30 -import java.util.List;
17.31 -import java.util.Map;
17.32 -
17.33 -/**
17.34 - * Converts command line arguments from String array to object.
17.35 - * Checks basic constraints (if only supported options are used and if they have correct number of
17.36 - * parameters)
17.37 - *
17.38 - * @author Ing. František Kučera (frantovo.cz)
17.39 - */
17.40 -public class CLIParser {
17.41 -
17.42 - public static final String TYPE_NAME_SEPARATOR = ":";
17.43 -
17.44 - public CLIOptions parseOptions(String[] args, InputStream in) throws CLIParserException {
17.45 - CLIOptions options = new CLIOptions();
17.46 -
17.47 - List<SQLType> numberedTypes = new ArrayList<>();
17.48 - Map<String, SQLType> namedTypes = new HashMap<>();
17.49 -
17.50 - for (int i = 0; i < args.length; i++) {
17.51 - String arg = args[i];
17.52 - switch (arg) {
17.53 - case Tokens.TYPES:
17.54 - String typesString = fetchNext(args, ++i);
17.55 -
17.56 - for (String oneType : typesString.split(",")) {
17.57 - int sepatratorIndex = oneType.indexOf(TYPE_NAME_SEPARATOR);
17.58 - if (sepatratorIndex == -1) {
17.59 - numberedTypes.add(getType(oneType.toUpperCase()));
17.60 - } else {
17.61 - String namePart = oneType.substring(0, sepatratorIndex).trim();
17.62 - String typePart = oneType.substring(sepatratorIndex + TYPE_NAME_SEPARATOR.length(), oneType.length());
17.63 - namedTypes.put(namePart, getType(typePart.toUpperCase()));
17.64 - }
17.65 - }
17.66 - break;
17.67 - case Tokens.NAME_PREFIX:
17.68 - options.setNamePrefix(fetchNext(args, ++i));
17.69 - break;
17.70 - case Tokens.NAME_SUFFIX:
17.71 - options.setNameSuffix(fetchNext(args, ++i));
17.72 - break;
17.73 - case Tokens.DB:
17.74 - options.setDatabaseName(fetchNext(args, ++i));
17.75 - break;
17.76 - case Tokens.SQL:
17.77 - options.setSql(fetchNext(args, ++i));
17.78 - break;
17.79 - case Tokens.SQL_IN:
17.80 - try {
17.81 - options.setSql(readString(in));
17.82 - } catch (IOException e) {
17.83 - throw new CLIParserException("Unable to read SQL from the input stream", e);
17.84 - }
17.85 - break;
17.86 - case Tokens.BATCH:
17.87 - options.setBatch(true);
17.88 - break;
17.89 - case Tokens.DATA: // --data is the last option
17.90 - for (i++; i < args.length; i++) {
17.91 - arg = args[i];
17.92 - Parameter parameter;
17.93 - if (numberedTypes.isEmpty()) {
17.94 - parameter = new Parameter(arg, null);
17.95 - } else {
17.96 - int paramIndex = options.getNumberedParameters().size();
17.97 - SQLType paramType;
17.98 - try {
17.99 - paramType = numberedTypes.get(paramIndex);
17.100 - } catch (IndexOutOfBoundsException e) {
17.101 - throw new CLIParserException("Missing type for parameter #" + paramIndex, e);
17.102 - } catch (NullPointerException e) {
17.103 - throw new CLIParserException("Invalid type definition for parameter #" + paramIndex, e);
17.104 - }
17.105 - parameter = new Parameter(arg, paramType);
17.106 - }
17.107 - options.addNumberedParameter(parameter);
17.108 - }
17.109 - break;
17.110 - case Tokens.DATA_NAMED:
17.111 - for (i++; i < args.length; i++) {
17.112 - String paramName = args[i];
17.113 - String paramValue = fetchNext(args, ++i);
17.114 - options.addNamedParameter(new NamedParameter(paramName, paramValue, namedTypes.get(paramName)));
17.115 - }
17.116 - break;
17.117 - case Tokens.FORMATTER:
17.118 - options.setFormatterName(fetchNext(args, ++i));
17.119 - break;
17.120 - case Tokens.DB_PROPERTY:
17.121 - options.addDatabaseProperty(new Property(fetchNext(args, ++i), fetchNext(args, ++i)));
17.122 - break;
17.123 - case Tokens.FORMATTER_PROPERTY:
17.124 - options.addFormatterProperty(new Property(fetchNext(args, ++i), fetchNext(args, ++i)));
17.125 - break;
17.126 - case Tokens.INFO_HELP:
17.127 - options.addShowInfo(InfoType.HELP);
17.128 - break;
17.129 - case Tokens.INFO_FORMATTERS:
17.130 - options.addShowInfo(InfoType.FORMATTERS);
17.131 - break;
17.132 - case Tokens.INFO_FORMATTER_PROPERTIES:
17.133 - options.addShowInfo(InfoType.FORMATTER_PROPERTIES);
17.134 - options.addFormatterNameToListProperties(fetchNext(args, ++i));
17.135 - break;
17.136 - case Tokens.INFO_LICENSE:
17.137 - options.addShowInfo(InfoType.LICENSE);
17.138 - break;
17.139 - case Tokens.INFO_JAVA_PROPERTIES:
17.140 - options.addShowInfo(InfoType.JAVA_PROPERTIES);
17.141 - break;
17.142 - case Tokens.INFO_ENVIRONMENT_VARIABLES:
17.143 - options.addShowInfo(InfoType.ENVIRONMENT_VARIABLES);
17.144 - break;
17.145 - case Tokens.INFO_TYPES:
17.146 - options.addShowInfo(InfoType.TYPES);
17.147 - break;
17.148 - case Tokens.INFO_VERSION:
17.149 - options.addShowInfo(InfoType.VERSION);
17.150 - break;
17.151 - case Tokens.INFO_JDBC_DRIVERS:
17.152 - options.addShowInfo(InfoType.JDBC_DRIVERS);
17.153 - break;
17.154 - case Tokens.INFO_JDBC_PROPERTIES:
17.155 - options.addShowInfo(InfoType.JDBC_PROPERTIES);
17.156 - options.addDatabaseNameToListProperties(fetchNext(args, ++i));
17.157 - break;
17.158 - case Tokens.INFO_DATABASES:
17.159 - options.addShowInfo(InfoType.DATABASES);
17.160 - break;
17.161 - case Tokens.INFO_CONNECTION:
17.162 - options.addShowInfo(InfoType.CONNECTION);
17.163 - options.addDatabaseNameToTest(fetchNext(args, ++i));
17.164 - break;
17.165 - default:
17.166 - throw new CLIParserException("Unknown option: " + arg);
17.167 - }
17.168 - }
17.169 - return options;
17.170 - }
17.171 -
17.172 - private String fetchNext(String[] args, int index) throws CLIParserException {
17.173 - if (index < args.length) {
17.174 - return args[index];
17.175 - } else {
17.176 - throw new CLIParserException("Expecting value for option: " + args[index - 1]);
17.177 - }
17.178 - }
17.179 -
17.180 - public static class Tokens {
17.181 -
17.182 - // bash-completion:options:
17.183 - public static final String DB = "--db"; // bash-completion:option // help: database name
17.184 - public static final String DB_PROPERTY = "--db-property"; // bash-completion:option // help: name and value
17.185 - public static final String SQL = "--sql"; // bash-completion:option // help: SQL query/command
17.186 - public static final String SQL_IN = "--sql-in"; // bash-completion:option // help: SQL query/command
17.187 - public static final String BATCH = "--batch"; // bash-completion:option // help: batch mode (no argument)
17.188 - public static final String DATA = "--data"; // bash-completion:option // help: list of ordinal parameters
17.189 - public static final String DATA_NAMED = "--data-named"; // bash-completion:option // help: list of named parameters
17.190 - public static final String NAME_PREFIX = "--name-prefix"; // bash-completion:option // help: parameter name prefix – regular expression
17.191 - public static final String NAME_SUFFIX = "--name-suffix"; // bash-completion:option // help: parameter name suffix – regular expression
17.192 - public static final String TYPES = "--types"; // bash-completion:option // help: comma separated list of parameter types
17.193 - public static final String FORMATTER = "--formatter"; // bash-completion:option // help: name of the output formatter
17.194 - public static final String FORMATTER_PROPERTY = "--formatter-property"; // bash-completion:option // help: name and value
17.195 - public static final String INFO_HELP = "--help"; // bash-completion:option // help: print this help
17.196 - public static final String INFO_VERSION = "--version"; // bash-completion:option // help: print version info
17.197 - public static final String INFO_LICENSE = "--license"; // bash-completion:option // help: print license
17.198 - public static final String INFO_JAVA_PROPERTIES = "--list-java-properties"; // bash-completion:option // help: list of Java system properties
17.199 - public static final String INFO_ENVIRONMENT_VARIABLES = "--list-environment-variables"; // bash-completion:option // help: list of environment variables
17.200 - public static final String INFO_FORMATTERS = "--list-formatters"; // bash-completion:option // help: print list of available formatters
17.201 - public static final String INFO_FORMATTER_PROPERTIES = "--list-formatter-properties"; // bash-completion:option // help: print list of available properties for given formatter
17.202 - public static final String INFO_TYPES = "--list-types"; // bash-completion:option // help: print list of available data types
17.203 - public static final String INFO_JDBC_DRIVERS = "--list-jdbc-drivers"; // bash-completion:option // help: list of available JDBC drivers
17.204 - public static final String INFO_JDBC_PROPERTIES = "--list-jdbc-properties"; // bash-completion:option // help: list of available JDBC properties for given database
17.205 - public static final String INFO_DATABASES = "--list-databases"; // bash-completion:option // help: print list of configured databases
17.206 - public static final String INFO_CONNECTION = "--test-connection"; // bash-completion:option // help: test connection to particular database
17.207 -
17.208 - private Tokens() {
17.209 - }
17.210 - }
17.211 -
17.212 - private SQLType getType(String typeString) throws CLIParserException {
17.213 - try {
17.214 - return SQLType.valueOf(typeString.trim());
17.215 - } catch (IllegalArgumentException e) {
17.216 - throw new CLIParserException("Unsupported type: " + typeString, e);
17.217 - }
17.218 - }
17.219 -}
18.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIParserException.java Mon Mar 04 17:06:42 2019 +0100
18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
18.3 @@ -1,40 +0,0 @@
18.4 -/**
18.5 - * SQL-DK
18.6 - * Copyright © 2013 František Kučera (frantovo.cz)
18.7 - *
18.8 - * This program is free software: you can redistribute it and/or modify
18.9 - * it under the terms of the GNU General Public License as published by
18.10 - * the Free Software Foundation, either version 3 of the License, or
18.11 - * (at your option) any later version.
18.12 - *
18.13 - * This program is distributed in the hope that it will be useful,
18.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
18.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18.16 - * GNU General Public License for more details.
18.17 - *
18.18 - * You should have received a copy of the GNU General Public License
18.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
18.20 - */
18.21 -package info.globalcode.sql.dk;
18.22 -
18.23 -/**
18.24 - *
18.25 - * @author Ing. František Kučera (frantovo.cz)
18.26 - */
18.27 -public class CLIParserException extends DKException {
18.28 -
18.29 - public CLIParserException() {
18.30 - }
18.31 -
18.32 - public CLIParserException(String message) {
18.33 - super(message);
18.34 - }
18.35 -
18.36 - public CLIParserException(Throwable cause) {
18.37 - super(cause);
18.38 - }
18.39 -
18.40 - public CLIParserException(String message, Throwable cause) {
18.41 - super(message, cause);
18.42 - }
18.43 -}
19.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIStarter.java Mon Mar 04 17:06:42 2019 +0100
19.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
19.3 @@ -1,274 +0,0 @@
19.4 -/**
19.5 - * SQL-DK
19.6 - * Copyright © 2013 František Kučera (frantovo.cz)
19.7 - *
19.8 - * This program is free software: you can redistribute it and/or modify
19.9 - * it under the terms of the GNU General Public License as published by
19.10 - * the Free Software Foundation, either version 3 of the License, or
19.11 - * (at your option) any later version.
19.12 - *
19.13 - * This program is distributed in the hope that it will be useful,
19.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
19.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19.16 - * GNU General Public License for more details.
19.17 - *
19.18 - * You should have received a copy of the GNU General Public License
19.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
19.20 - */
19.21 -package info.globalcode.sql.dk;
19.22 -
19.23 -import info.globalcode.sql.dk.configuration.ConfigurationProvider;
19.24 -import info.globalcode.sql.dk.CLIOptions.MODE;
19.25 -import info.globalcode.sql.dk.batch.Batch;
19.26 -import info.globalcode.sql.dk.batch.BatchDecoder;
19.27 -import info.globalcode.sql.dk.batch.BatchException;
19.28 -import info.globalcode.sql.dk.batch.BatchEncoder;
19.29 -import info.globalcode.sql.dk.configuration.Configuration;
19.30 -import info.globalcode.sql.dk.configuration.ConfigurationException;
19.31 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
19.32 -import info.globalcode.sql.dk.configuration.FormatterDefinition;
19.33 -import info.globalcode.sql.dk.configuration.Loader;
19.34 -import info.globalcode.sql.dk.configuration.NameIdentified;
19.35 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
19.36 -import info.globalcode.sql.dk.formatting.Formatter;
19.37 -import info.globalcode.sql.dk.formatting.FormatterContext;
19.38 -import info.globalcode.sql.dk.formatting.FormatterException;
19.39 -import info.globalcode.sql.dk.jmx.ConnectionManagement;
19.40 -import info.globalcode.sql.dk.jmx.ManagementUtils;
19.41 -import java.io.File;
19.42 -import java.io.FileNotFoundException;
19.43 -import java.io.IOException;
19.44 -import java.io.PrintStream;
19.45 -import java.io.PrintWriter;
19.46 -import java.sql.SQLException;
19.47 -import java.util.Collection;
19.48 -import java.util.Collections;
19.49 -import java.util.List;
19.50 -import java.util.logging.Level;
19.51 -import java.util.logging.LogRecord;
19.52 -import java.util.logging.Logger;
19.53 -
19.54 -/**
19.55 - * Entry point of the command line interface of SQL-DK.
19.56 - *
19.57 - * @author Ing. František Kučera (frantovo.cz)
19.58 - */
19.59 -public class CLIStarter implements ConfigurationProvider {
19.60 -
19.61 - // help:exit-codes
19.62 - public static final int EXIT_SUCCESS = 0; // doc:success
19.63 - public static final int EXIT_UNEXPECTED_ERROR = 1; // doc:unexpected error (probably bug)
19.64 - // 2 is reserved: http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF
19.65 - public static final int EXIT_SQL_ERROR = 3; // doc:SQL error
19.66 - public static final int EXIT_CLI_PARSE_ERROR = 4; // doc:CLI options parse error
19.67 - public static final int EXIT_CLI_VALIDATE_ERROR = 5; // doc:CLI options validation error
19.68 - public static final int EXIT_CONFIGURATION_ERROR = 6; // doc:configuration error
19.69 - public static final int EXIT_FORMATTING_ERROR = 7; // doc:formatting error
19.70 - public static final int EXIT_BATCH_ERROR = 8; // doc:batch error
19.71 - private static final Logger log = Logger.getLogger(CLIStarter.class.getName());
19.72 - private final CLIOptions options;
19.73 - private final Loader configurationLoader = new Loader();
19.74 - private Configuration configuration;
19.75 -
19.76 - public static void main(String[] args) {
19.77 - log.log(Level.FINE, "Starting " + Constants.PROGRAM_NAME);
19.78 - int exitCode;
19.79 -
19.80 - if (args.length == 0) {
19.81 - args = new String[]{CLIParser.Tokens.INFO_HELP};
19.82 - }
19.83 -
19.84 - try {
19.85 - CLIParser parser = new CLIParser();
19.86 - CLIOptions options = parser.parseOptions(args, System.in);
19.87 - options.validate();
19.88 - CLIStarter starter = new CLIStarter(options);
19.89 - starter.installDefaultConfiguration();
19.90 - starter.process();
19.91 - log.log(Level.FINE, "All done");
19.92 - exitCode = EXIT_SUCCESS;
19.93 - } catch (CLIParserException e) {
19.94 - log.log(Level.SEVERE, "Unable to parse CLI options", e);
19.95 - exitCode = EXIT_CLI_PARSE_ERROR;
19.96 - } catch (InvalidOptionsException e) {
19.97 - log.log(Level.SEVERE, "Invalid CLI options", e);
19.98 - for (InvalidOptionsException.OptionProblem p : e.getProblems()) {
19.99 - LogRecord r = new LogRecord(Level.SEVERE, "Option problem: {0}");
19.100 - r.setThrown(p.getException());
19.101 - r.setParameters(new Object[]{p.getDescription()});
19.102 - log.log(r);
19.103 - }
19.104 - exitCode = EXIT_CLI_VALIDATE_ERROR;
19.105 - } catch (ConfigurationException e) {
19.106 - log.log(Level.SEVERE, "Configuration problem", e);
19.107 - exitCode = EXIT_CONFIGURATION_ERROR;
19.108 - } catch (SQLException e) {
19.109 - log.log(Level.SEVERE, "SQL problem", e);
19.110 - exitCode = EXIT_SQL_ERROR;
19.111 - } catch (FormatterException e) {
19.112 - log.log(Level.SEVERE, "Formatting problem", e);
19.113 - exitCode = EXIT_FORMATTING_ERROR;
19.114 - } catch (BatchException e) {
19.115 - log.log(Level.SEVERE, "Batch problem", e);
19.116 - exitCode = EXIT_BATCH_ERROR;
19.117 - }
19.118 -
19.119 - System.exit(exitCode);
19.120 - }
19.121 -
19.122 - public CLIStarter(CLIOptions options) {
19.123 - this.options = options;
19.124 - }
19.125 -
19.126 - private void process() throws ConfigurationException, SQLException, FormatterException, BatchException {
19.127 - MODE mode = options.getMode();
19.128 -
19.129 - /** Show info */
19.130 - if (!options.getShowInfo().isEmpty()) {
19.131 - PrintStream infoOut = mode == MODE.JUST_SHOW_INFO ? System.out : System.err;
19.132 - InfoLister infoLister = new InfoLister(infoOut, this, options);
19.133 - infoLister.showInfo();
19.134 - }
19.135 -
19.136 - switch (mode) {
19.137 - case QUERY_NOW:
19.138 - processQueryNow();
19.139 - break;
19.140 - case PREPARE_BATCH:
19.141 - processPrepareBatch();
19.142 - break;
19.143 - case EXECUTE_BATCH:
19.144 - processExecuteBatch();
19.145 - break;
19.146 - case JUST_SHOW_INFO:
19.147 - // already done above
19.148 - break;
19.149 - default:
19.150 - log.log(Level.SEVERE, "Unsupported mode: {0}", mode);
19.151 - break;
19.152 - }
19.153 -
19.154 - generateBashCompletion();
19.155 - }
19.156 -
19.157 - private void processQueryNow() throws ConfigurationException, SQLException, FormatterException {
19.158 - DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName());
19.159 - FormatterDefinition fd = configuration.getFormatter(options.getFormatterName());
19.160 - ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName());
19.161 -
19.162 - try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) {
19.163 - log.log(Level.FINE, "Database connected");
19.164 - try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) {
19.165 - c.executeQuery(options.getSQLCommand(), f);
19.166 - }
19.167 - }
19.168 - }
19.169 -
19.170 - private void processPrepareBatch() throws BatchException {
19.171 - BatchEncoder enc = new BatchEncoder();
19.172 - int length = enc.encode(options.getSQLCommand(), options.getOutputStream());
19.173 - log.log(Level.FINE, "Prepared batch size: {0} bytes", length);
19.174 - }
19.175 -
19.176 - private void processExecuteBatch() throws ConfigurationException, SQLException, FormatterException, BatchException {
19.177 - BatchDecoder dec = new BatchDecoder();
19.178 - Batch b = dec.decode(options.getInputStream());
19.179 -
19.180 - DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName());
19.181 - FormatterDefinition fd = configuration.getFormatter(options.getFormatterName());
19.182 - ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName());
19.183 -
19.184 - try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) {
19.185 - log.log(Level.FINE, "Database connected");
19.186 - try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) {
19.187 - c.executeBatch(b, f);
19.188 - }
19.189 - }
19.190 - }
19.191 -
19.192 - @Override
19.193 - public Configuration getConfiguration() throws ConfigurationException {
19.194 - if (configuration == null) {
19.195 - configuration = configurationLoader.loadConfiguration();
19.196 - }
19.197 - return configuration;
19.198 - }
19.199 -
19.200 - private void installDefaultConfiguration() throws ConfigurationException {
19.201 - Constants.DIR.mkdir();
19.202 -
19.203 - if (Constants.CONFIG_FILE.exists()) {
19.204 - log.log(Level.FINER, "Config file already exists: {0}", Constants.CONFIG_FILE);
19.205 - } else {
19.206 - try {
19.207 - Functions.installResource(Constants.EXAMPLE_CONFIG_FILE, Constants.CONFIG_FILE);
19.208 - log.log(Level.FINE, "Installing default config file: {0}", Constants.CONFIG_FILE);
19.209 - } catch (IOException e) {
19.210 - throw new ConfigurationException("Unable to write example configuration to " + Constants.CONFIG_FILE, e);
19.211 - }
19.212 - }
19.213 - }
19.214 -
19.215 - private void generateBashCompletion() {
19.216 - if (configuration == null) {
19.217 - log.log(Level.FINER, "Not writing Bash completion helper files. In order to generate these files please run some command which requires configuration.");
19.218 - } else {
19.219 - try {
19.220 - File dir = new File(Constants.DIR, "bash-completion");
19.221 - dir.mkdir();
19.222 - writeBashCompletionHelperFile(configuration.getDatabases(), new File(dir, "databases"));
19.223 - writeBashCompletionHelperFile(configuration.getAllFormatters(), new File(dir, "formatters"));
19.224 - writeBashCompletionHelperFileForFormatterProperties(new File(dir, "formatter-properties"));
19.225 - } catch (Exception e) {
19.226 - log.log(Level.WARNING, "Unable to generate Bash completion helper files", e);
19.227 - }
19.228 - }
19.229 - }
19.230 -
19.231 - private void writeBashCompletionHelperFile(Collection<? extends NameIdentified> items, File target) throws FileNotFoundException {
19.232 - if (Constants.CONFIG_FILE.lastModified() > target.lastModified()) {
19.233 - try (PrintWriter fw = new PrintWriter(target)) {
19.234 - for (NameIdentified dd : items) {
19.235 - fw.println(dd.getName());
19.236 - }
19.237 - fw.close();
19.238 - log.log(Level.FINE, "Bash completion helper file was written: {0}", target);
19.239 - }
19.240 - } else {
19.241 - log.log(Level.FINER, "Not writing Bash completion helper file: {0} because configuration {1} has not been changed", new Object[]{target, Constants.CONFIG_FILE});
19.242 - }
19.243 - }
19.244 -
19.245 - private void writeBashCompletionHelperFileForFormatterProperties(File formattersDir) throws ClassNotFoundException, FileNotFoundException {
19.246 - if (Constants.CONFIG_FILE.lastModified() > formattersDir.lastModified()) {
19.247 - // TODO: delete old directory
19.248 - formattersDir.mkdir();
19.249 - for (FormatterDefinition fd : configuration.getAllFormatters()) {
19.250 - File formatterDir = new File(formattersDir, fd.getName());
19.251 - formatterDir.mkdir();
19.252 -
19.253 - Class<Formatter> formatterClass = (Class<Formatter>) Class.forName(fd.getClassName());
19.254 - List<Class<? extends Formatter>> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class);
19.255 - Collections.reverse(hierarchy);
19.256 - for (Class<? extends Formatter> c : hierarchy) {
19.257 - for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) {
19.258 - File propertyDir = new File(formatterDir, p.name());
19.259 - propertyDir.mkdir();
19.260 - File choicesFile = new File(propertyDir, "choices");
19.261 - try (PrintWriter fw = new PrintWriter(choicesFile)) {
19.262 - // TODO: refactor, move
19.263 - if (p.type() == Boolean.class) {
19.264 - fw.println("true");
19.265 - fw.println("false");
19.266 - }
19.267 - }
19.268 - }
19.269 - }
19.270 - }
19.271 - log.log(Level.FINE, "Bash completion helper files was written in: {0}", formattersDir);
19.272 - } else {
19.273 - log.log(Level.FINER, "Not writing Bash completion helper directory: {0} because configuration {1} has not been changed", new Object[]{formattersDir, Constants.CONFIG_FILE});
19.274 - }
19.275 -
19.276 - }
19.277 -}
20.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/ColorfulPrintWriter.java Mon Mar 04 17:06:42 2019 +0100
20.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
20.3 @@ -1,358 +0,0 @@
20.4 -/**
20.5 - * SQL-DK
20.6 - * Copyright © 2013 František Kučera (frantovo.cz)
20.7 - *
20.8 - * This program is free software: you can redistribute it and/or modify
20.9 - * it under the terms of the GNU General Public License as published by
20.10 - * the Free Software Foundation, either version 3 of the License, or
20.11 - * (at your option) any later version.
20.12 - *
20.13 - * This program is distributed in the hope that it will be useful,
20.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
20.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20.16 - * GNU General Public License for more details.
20.17 - *
20.18 - * You should have received a copy of the GNU General Public License
20.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
20.20 - */
20.21 -package info.globalcode.sql.dk;
20.22 -
20.23 -import java.io.File;
20.24 -import java.io.FileNotFoundException;
20.25 -import java.io.OutputStream;
20.26 -import java.io.PrintWriter;
20.27 -import java.io.UnsupportedEncodingException;
20.28 -import java.io.Writer;
20.29 -import java.util.EnumSet;
20.30 -
20.31 -/**
20.32 - * PrintWriter with convenience methods for printing color and formatted text.
20.33 - *
20.34 - * Uses ANSI Escape Sequences.
20.35 - * See: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
20.36 - *
20.37 - * @author Ing. František Kučera (frantovo.cz)
20.38 - */
20.39 -public class ColorfulPrintWriter extends PrintWriter {
20.40 -
20.41 - public enum TerminalColor {
20.42 -
20.43 - Black(30, 40),
20.44 - Red(31, 41),
20.45 - Green(32, 42),
20.46 - Yellow(33, 43),
20.47 - Blue(34, 44),
20.48 - Magenta(35, 45),
20.49 - Cyan(36, 46),
20.50 - White(37, 47);
20.51 - private final int foregroundCode;
20.52 - private final int backgroundCode;
20.53 -
20.54 - private TerminalColor(int foregroundCode, int backgroundCode) {
20.55 - this.foregroundCode = foregroundCode;
20.56 - this.backgroundCode = backgroundCode;
20.57 - }
20.58 -
20.59 - public int getForegroundCode() {
20.60 - return foregroundCode;
20.61 - }
20.62 -
20.63 - public int getBackgroundCode() {
20.64 - return backgroundCode;
20.65 - }
20.66 - }
20.67 -
20.68 - public enum TerminalStyle {
20.69 -
20.70 - Reset(0),
20.71 - Bright(1),
20.72 - Dim(2),
20.73 - Underscore(4),
20.74 - Blink(5),
20.75 - Reverse(7),
20.76 - Hidden(8);
20.77 - private int code;
20.78 -
20.79 - private TerminalStyle(int code) {
20.80 - this.code = code;
20.81 - }
20.82 -
20.83 - public int getCode() {
20.84 - return code;
20.85 - }
20.86 - }
20.87 - private final boolean COLOR_ENABLED;
20.88 - private boolean colorful = true;
20.89 -
20.90 - public void setStyle(TerminalStyle style) {
20.91 - setStyle(EnumSet.of(style));
20.92 - }
20.93 -
20.94 - public void setStyle(EnumSet<TerminalStyle> styles) {
20.95 - printCodes(getStyleCodes(styles));
20.96 - }
20.97 -
20.98 - private static int[] getStyleCodes(EnumSet<TerminalStyle> styles) {
20.99 - int[] array = new int[styles.size()];
20.100 - int i = 0;
20.101 - for (TerminalStyle s : styles) {
20.102 - array[i++] = s.getCode();
20.103 - }
20.104 - return array;
20.105 - }
20.106 -
20.107 - /**
20.108 - * Print (usually audible) bell code (\007, \a, ^G)
20.109 - */
20.110 - public void bell() {
20.111 - print("\007");
20.112 - }
20.113 -
20.114 - /**
20.115 - * Eat the last character
20.116 - */
20.117 - public void backspace() {
20.118 - print("\b");
20.119 - }
20.120 -
20.121 - /**
20.122 - * Eat n last characters
20.123 - *
20.124 - * @param count n
20.125 - */
20.126 - public void backspace(int count) {
20.127 - for (int i = 0; i < count; i++) {
20.128 - backspace();
20.129 - }
20.130 - }
20.131 -
20.132 - /**
20.133 - * With 100 ms delay and all colors.
20.134 - *
20.135 - * @see #printRainbow(java.lang.String, int,
20.136 - * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[])
20.137 - */
20.138 - public void printRainbow(String string) {
20.139 - printRainbow(string, 100);
20.140 - }
20.141 -
20.142 - /**
20.143 - * With all colors.
20.144 - *
20.145 - * @see #printRainbow(java.lang.String, int,
20.146 - * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[])
20.147 - */
20.148 - public void printRainbow(String string, int delay) {
20.149 - printRainbow(string, delay, TerminalColor.values());
20.150 - }
20.151 -
20.152 - /**
20.153 - * Prints rainbow text – (re)writes same text subsequently in given colors and then in default
20.154 - * color.
20.155 - *
20.156 - * @param string text to be printed, should not contain \n new line (then rainbow does not work
20.157 - * – use println() after printRainbow() instead)
20.158 - * @param delay delay between rewrites
20.159 - * @param colors list of colors to be used
20.160 - */
20.161 - public void printRainbow(String string, int delay, TerminalColor... colors) {
20.162 - for (TerminalColor c : colors) {
20.163 - print(c, string);
20.164 - try {
20.165 - Thread.sleep(delay);
20.166 - } catch (InterruptedException e) {
20.167 - // no time to sleep
20.168 - break;
20.169 - }
20.170 - backspace(string.length());
20.171 - flush();
20.172 - }
20.173 - print(string);
20.174 - }
20.175 -
20.176 - public void setForegroundColor(TerminalColor color) {
20.177 - printCodes(color.getForegroundCode());
20.178 - }
20.179 -
20.180 - public void setBackgroundColor(TerminalColor color) {
20.181 - printCodes(color.getBackgroundCode());
20.182 - }
20.183 -
20.184 - public void print(TerminalColor foregroundColor, String string) {
20.185 - setForegroundColor(foregroundColor);
20.186 - print(string);
20.187 - resetAll();
20.188 - }
20.189 -
20.190 - public void println(TerminalColor foregroundColor, String string) {
20.191 - print(foregroundColor, string);
20.192 - println();
20.193 - }
20.194 -
20.195 - public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) {
20.196 - setForegroundColor(foregroundColor);
20.197 - setBackgroundColor(backgroundColor);
20.198 - print(string);
20.199 - resetAll();
20.200 - }
20.201 -
20.202 - public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) {
20.203 - print(foregroundColor, backgroundColor, string);
20.204 - println();
20.205 - }
20.206 -
20.207 - public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet<TerminalStyle> styles, String string) {
20.208 - setForegroundColor(foregroundColor);
20.209 - setBackgroundColor(backgroundColor);
20.210 - setStyle(styles);
20.211 - print(string);
20.212 - resetAll();
20.213 - }
20.214 -
20.215 - public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet<TerminalStyle> styles, String string) {
20.216 - print(foregroundColor, backgroundColor, styles, string);
20.217 - println();
20.218 - }
20.219 -
20.220 - public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) {
20.221 - print(foregroundColor, backgroundColor, EnumSet.of(style), string);
20.222 - }
20.223 -
20.224 - public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) {
20.225 - print(foregroundColor, backgroundColor, style, string);
20.226 - println();
20.227 - }
20.228 -
20.229 - public void print(TerminalColor foregroundColor, EnumSet<TerminalStyle> styles, String string) {
20.230 - setForegroundColor(foregroundColor);
20.231 - setStyle(styles);
20.232 - print(string);
20.233 - resetAll();
20.234 - }
20.235 -
20.236 - public void println(TerminalColor foregroundColor, EnumSet<TerminalStyle> styles, String string) {
20.237 - print(foregroundColor, styles, string);
20.238 - println();
20.239 - }
20.240 -
20.241 - public void print(TerminalColor foregroundColor, TerminalStyle style, String string) {
20.242 - print(foregroundColor, EnumSet.of(style), string);
20.243 - }
20.244 -
20.245 - public void println(TerminalColor foregroundColor, TerminalStyle style, String string) {
20.246 - print(foregroundColor, style, string);
20.247 - println();
20.248 - }
20.249 -
20.250 - public void print(EnumSet<TerminalStyle> styles, String string) {
20.251 - setStyle(styles);
20.252 - print(string);
20.253 - resetAll();
20.254 - }
20.255 -
20.256 - public void println(EnumSet<TerminalStyle> styles, String string) {
20.257 - print(styles, string);
20.258 - println();
20.259 - }
20.260 -
20.261 - public void print(TerminalStyle style, String string) {
20.262 - print(EnumSet.of(style), string);
20.263 - }
20.264 -
20.265 - public void println(TerminalStyle style, String string) {
20.266 - print(style, string);
20.267 - println();
20.268 - }
20.269 -
20.270 - public void resetAll() {
20.271 - printCodes(TerminalStyle.Reset.code);
20.272 - }
20.273 -
20.274 - private void printCodes(int... codes) {
20.275 - if (COLOR_ENABLED && colorful) {
20.276 - print("\033[");
20.277 - for (int i = 0; i < codes.length; i++) {
20.278 - print(codes[i]);
20.279 - if (i < codes.length - 1 && codes.length > 1) {
20.280 - print(";");
20.281 - }
20.282 - }
20.283 - print("m");
20.284 - }
20.285 - }
20.286 -
20.287 - /**
20.288 - * Colors can be switched on/off during usage of this writer.
20.289 - *
20.290 - * @return whether colors are currently turned on
20.291 - * @see #isColorEnabled()
20.292 - */
20.293 - public boolean isColorful() {
20.294 - return colorful;
20.295 - }
20.296 -
20.297 - /**
20.298 - * Collors might be definitively disabled in constructor. If not, they can be turned on/off
20.299 - * during usage of this writer by {@linkplain #setColorful(boolean)}
20.300 - *
20.301 - * @return whether colors are allowed for this instance of this class
20.302 - * @see #isColorful()
20.303 - */
20.304 - public boolean isColorEnabled() {
20.305 - return COLOR_ENABLED;
20.306 - }
20.307 -
20.308 - /**
20.309 - * @see #isColorful()
20.310 - * @see #isColorEnabled()
20.311 - */
20.312 - public void setColorful(boolean colorful) {
20.313 - this.colorful = colorful;
20.314 - }
20.315 -
20.316 - public ColorfulPrintWriter(File file) throws FileNotFoundException {
20.317 - super(file);
20.318 - COLOR_ENABLED = true;
20.319 - }
20.320 -
20.321 - public ColorfulPrintWriter(OutputStream out) {
20.322 - super(out);
20.323 - COLOR_ENABLED = true;
20.324 - }
20.325 -
20.326 - public ColorfulPrintWriter(String fileName) throws FileNotFoundException {
20.327 - super(fileName);
20.328 - COLOR_ENABLED = true;
20.329 - }
20.330 -
20.331 - public ColorfulPrintWriter(Writer out) {
20.332 - super(out);
20.333 - COLOR_ENABLED = true;
20.334 - }
20.335 -
20.336 - public ColorfulPrintWriter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException {
20.337 - super(file, csn);
20.338 - COLOR_ENABLED = true;
20.339 - }
20.340 -
20.341 - /**
20.342 - * @param colorEnabled colors might be definitively disabled by this option – this might be more
20.343 - * optimalizable than dynamic turning off colors by {@linkplain #setColorful(boolean)} which is
20.344 - * not definitive (colors can be turned on during live of this instance). This might be useful
20.345 - * if you need an instance of this class but don't need colors at all.
20.346 - */
20.347 - public ColorfulPrintWriter(OutputStream out, boolean autoFlush, boolean colorEnabled) {
20.348 - super(out, autoFlush);
20.349 - COLOR_ENABLED = colorEnabled;
20.350 - }
20.351 -
20.352 - public ColorfulPrintWriter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException {
20.353 - super(fileName, csn);
20.354 - COLOR_ENABLED = true;
20.355 - }
20.356 -
20.357 - public ColorfulPrintWriter(Writer out, boolean autoFlush) {
20.358 - super(out, autoFlush);
20.359 - COLOR_ENABLED = true;
20.360 - }
20.361 -}
21.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/Constants.java Mon Mar 04 17:06:42 2019 +0100
21.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
21.3 @@ -1,44 +0,0 @@
21.4 -/**
21.5 - * SQL-DK
21.6 - * Copyright © 2013 František Kučera (frantovo.cz)
21.7 - *
21.8 - * This program is free software: you can redistribute it and/or modify
21.9 - * it under the terms of the GNU General Public License as published by
21.10 - * the Free Software Foundation, either version 3 of the License, or
21.11 - * (at your option) any later version.
21.12 - *
21.13 - * This program is distributed in the hope that it will be useful,
21.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
21.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21.16 - * GNU General Public License for more details.
21.17 - *
21.18 - * You should have received a copy of the GNU General Public License
21.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
21.20 - */
21.21 -package info.globalcode.sql.dk;
21.22 -
21.23 -import java.io.File;
21.24 -
21.25 -/**
21.26 - *
21.27 - * @author Ing. František Kučera (frantovo.cz)
21.28 - */
21.29 -public class Constants {
21.30 -
21.31 - public static final String PROGRAM_NAME = "SQL-DK";
21.32 - public static final String JAVA_PACKAGE = Constants.class.getPackage().getName();
21.33 - public static final String WEBSITE = "https://sql-dk.globalcode.info/";
21.34 - public static final String LICENSE_FILE = "info/globalcode/sql/dk/license.txt";
21.35 - public static final String VERSION_FILE = "info/globalcode/sql/dk/version.txt";
21.36 - public static final String HELP_FILE = "info/globalcode/sql/dk/help.txt";
21.37 - private static final File HOME_DIR = new File(System.getProperty("user.home"));
21.38 - /**
21.39 - * Directory where config and log files are stored.
21.40 - */
21.41 - public static final File DIR = new File(HOME_DIR, ".sql-dk"); // bash-completion:dir
21.42 - public static final File CONFIG_FILE = new File(DIR, "config.xml");
21.43 - public static final String EXAMPLE_CONFIG_FILE = "info/globalcode/sql/dk/example-config.xml";
21.44 -
21.45 - private Constants() {
21.46 - }
21.47 -}
22.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/DKException.java Mon Mar 04 17:06:42 2019 +0100
22.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
22.3 @@ -1,41 +0,0 @@
22.4 -/**
22.5 - * SQL-DK
22.6 - * Copyright © 2013 František Kučera (frantovo.cz)
22.7 - *
22.8 - * This program is free software: you can redistribute it and/or modify
22.9 - * it under the terms of the GNU General Public License as published by
22.10 - * the Free Software Foundation, either version 3 of the License, or
22.11 - * (at your option) any later version.
22.12 - *
22.13 - * This program is distributed in the hope that it will be useful,
22.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
22.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22.16 - * GNU General Public License for more details.
22.17 - *
22.18 - * You should have received a copy of the GNU General Public License
22.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
22.20 - */
22.21 -package info.globalcode.sql.dk;
22.22 -
22.23 -/**
22.24 - * TODO: GEC
22.25 - *
22.26 - * @author Ing. František Kučera (frantovo.cz)
22.27 - */
22.28 -public class DKException extends Exception {
22.29 -
22.30 - public DKException() {
22.31 - }
22.32 -
22.33 - public DKException(String message) {
22.34 - super(message);
22.35 - }
22.36 -
22.37 - public DKException(Throwable cause) {
22.38 - super(cause);
22.39 - }
22.40 -
22.41 - public DKException(String message, Throwable cause) {
22.42 - super(message, cause);
22.43 - }
22.44 -}
23.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/DatabaseConnection.java Mon Mar 04 17:06:42 2019 +0100
23.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
23.3 @@ -1,192 +0,0 @@
23.4 -/**
23.5 - * SQL-DK
23.6 - * Copyright © 2013 František Kučera (frantovo.cz)
23.7 - *
23.8 - * This program is free software: you can redistribute it and/or modify
23.9 - * it under the terms of the GNU General Public License as published by
23.10 - * the Free Software Foundation, either version 3 of the License, or
23.11 - * (at your option) any later version.
23.12 - *
23.13 - * This program is distributed in the hope that it will be useful,
23.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
23.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23.16 - * GNU General Public License for more details.
23.17 - *
23.18 - * You should have received a copy of the GNU General Public License
23.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
23.20 - */
23.21 -package info.globalcode.sql.dk;
23.22 -
23.23 -import static info.globalcode.sql.dk.jmx.ConnectionManagement.incrementCounter;
23.24 -import static info.globalcode.sql.dk.jmx.ConnectionManagement.resetCounter;
23.25 -import info.globalcode.sql.dk.batch.Batch;
23.26 -import info.globalcode.sql.dk.batch.BatchException;
23.27 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
23.28 -import info.globalcode.sql.dk.configuration.Loader;
23.29 -import info.globalcode.sql.dk.configuration.Properties;
23.30 -import info.globalcode.sql.dk.formatting.ColumnsHeader;
23.31 -import info.globalcode.sql.dk.formatting.Formatter;
23.32 -import info.globalcode.sql.dk.jmx.ConnectionManagement;
23.33 -import info.globalcode.sql.dk.jmx.ConnectionManagement.COUNTER;
23.34 -import java.sql.Connection;
23.35 -import java.sql.PreparedStatement;
23.36 -import java.sql.ResultSet;
23.37 -import java.sql.SQLException;
23.38 -import java.sql.SQLWarning;
23.39 -import java.util.logging.Level;
23.40 -import java.util.logging.Logger;
23.41 -
23.42 -/**
23.43 - * Represents connected database. Is derived from {@linkplain DatabaseDefinition}.
23.44 - * Wraps {@linkplain Connection}.
23.45 - *
23.46 - * Is responsible for executing {@linkplain SQLCommand} and passing results to the
23.47 - * {@linkplain Formatter}.
23.48 - *
23.49 - * @author Ing. František Kučera (frantovo.cz)
23.50 - */
23.51 -public class DatabaseConnection implements AutoCloseable {
23.52 -
23.53 - private static final Logger log = Logger.getLogger(DatabaseConnection.class.getName());
23.54 - public static final String JDBC_PROPERTY_USER = "user";
23.55 - public static final String JDBC_PROPERTY_PASSWORD = "password";
23.56 - private final DatabaseDefinition databaseDefinition;
23.57 - private final Connection connection;
23.58 - private final Properties properties;
23.59 - /**
23.60 - * Could be null = JMX is disabled → must check, see functions in
23.61 - * {@linkplain ConnectionManagement}
23.62 - */
23.63 - private final ConnectionManagement connectionMBean;
23.64 -
23.65 - /**
23.66 - *
23.67 - * @param databaseDefinition DB url, name, password etc.
23.68 - * @param properties additional properties from CLI
23.69 - * @param connectionMBean JMX management bean | null = disabled JMX reporting
23.70 - * @throws SQLException
23.71 - */
23.72 - public DatabaseConnection(DatabaseDefinition databaseDefinition, Properties properties, ConnectionManagement connectionMBean) throws SQLException {
23.73 - this.databaseDefinition = databaseDefinition;
23.74 - this.properties = properties;
23.75 - this.connectionMBean = connectionMBean;
23.76 - this.connection = Loader.jdbcConnect(databaseDefinition, properties);
23.77 - }
23.78 -
23.79 - public void executeQuery(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
23.80 - formatter.writeStartBatch();
23.81 - formatter.writeStartDatabase(databaseDefinition);
23.82 - formatter.writeStartStatement();
23.83 - formatter.writeQuery(sqlCommand.getQuery());
23.84 - formatter.writeParameters(sqlCommand.getParameters());
23.85 - processCommand(sqlCommand, formatter);
23.86 - formatter.writeEndStatement();
23.87 - formatter.writeEndDatabase();
23.88 - formatter.writeEndBatch();
23.89 - }
23.90 -
23.91 - public void executeBatch(Batch batch, Formatter formatter) throws SQLException, BatchException {
23.92 - formatter.writeStartBatch();
23.93 - formatter.writeStartDatabase(databaseDefinition);
23.94 - while (batch.hasNext()) {
23.95 - SQLCommand sqlCommand = batch.next();
23.96 - formatter.writeStartStatement();
23.97 - formatter.writeQuery(sqlCommand.getQuery());
23.98 - formatter.writeParameters(sqlCommand.getParameters());
23.99 - processCommand(sqlCommand, formatter);
23.100 - formatter.writeEndStatement();
23.101 - }
23.102 - formatter.writeEndDatabase();
23.103 - formatter.writeEndBatch();
23.104 - }
23.105 -
23.106 - private void processCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
23.107 - incrementCounter(connectionMBean, COUNTER.COMMAND);
23.108 - resetCounter(connectionMBean, COUNTER.RECORD_CURRENT);
23.109 -
23.110 - try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) {
23.111 - log.log(Level.FINE, "Statement prepared");
23.112 - sqlCommand.parametrize(ps);
23.113 -
23.114 - boolean isRS = ps.execute();
23.115 - log.log(Level.FINE, "Statement executed");
23.116 - if (isRS) {
23.117 - try (ResultSet rs = ps.getResultSet()) {
23.118 - processResultSet(rs, formatter);
23.119 - }
23.120 - } else {
23.121 - processUpdateResult(ps, formatter);
23.122 - }
23.123 - logWarnings(ps);
23.124 -
23.125 - while (ps.getMoreResults() || ps.getUpdateCount() > -1) {
23.126 - ResultSet rs = ps.getResultSet();
23.127 - if (rs == null) {
23.128 - processUpdateResult(ps, formatter);
23.129 - } else {
23.130 - processResultSet(rs, formatter);
23.131 - rs.close();
23.132 - }
23.133 - logWarnings(ps);
23.134 - }
23.135 - }
23.136 - }
23.137 -
23.138 - private void processUpdateResult(PreparedStatement ps, Formatter formatter) throws SQLException {
23.139 - formatter.writeUpdatesResult(ps.getUpdateCount());
23.140 - }
23.141 -
23.142 - private void processResultSet(ResultSet rs, Formatter formatter) throws SQLException {
23.143 - formatter.writeStartResultSet(new ColumnsHeader(rs.getMetaData()));
23.144 -
23.145 - int columnCount = rs.getMetaData().getColumnCount();
23.146 -
23.147 - while (rs.next()) {
23.148 - incrementCounter(connectionMBean, COUNTER.RECORD_CURRENT);
23.149 - incrementCounter(connectionMBean, COUNTER.RECORD_TOTAL);
23.150 -
23.151 - formatter.writeStartRow();
23.152 -
23.153 - for (int i = 1; i <= columnCount; i++) {
23.154 - formatter.writeColumnValue(rs.getObject(i));
23.155 - }
23.156 -
23.157 - formatter.writeEndRow();
23.158 - }
23.159 -
23.160 - formatter.writeEndResultSet();
23.161 - }
23.162 -
23.163 - private void logWarnings(PreparedStatement ps) throws SQLException {
23.164 - SQLWarning w = ps.getWarnings();
23.165 - while (w != null) {
23.166 - log.log(Level.WARNING, "SQL: {0}", w.getLocalizedMessage());
23.167 - w = w.getNextWarning();
23.168 - }
23.169 - ps.clearWarnings();
23.170 - }
23.171 -
23.172 - /**
23.173 - * Tests if this connection is live.
23.174 - *
23.175 - * @return true if test was successful
23.176 - * @throws SQLException if test fails
23.177 - */
23.178 - public boolean test() throws SQLException {
23.179 - connection.getAutoCommit();
23.180 - return true;
23.181 - }
23.182 -
23.183 - public String getProductName() throws SQLException {
23.184 - return connection.getMetaData().getDatabaseProductName();
23.185 - }
23.186 -
23.187 - public String getProductVersion() throws SQLException {
23.188 - return connection.getMetaData().getDatabaseProductVersion();
23.189 - }
23.190 -
23.191 - @Override
23.192 - public void close() throws SQLException {
23.193 - connection.close();
23.194 - }
23.195 -}
24.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/Functions.java Mon Mar 04 17:06:42 2019 +0100
24.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
24.3 @@ -1,254 +0,0 @@
24.4 -/**
24.5 - * SQL-DK
24.6 - * Copyright © 2013 František Kučera (frantovo.cz)
24.7 - *
24.8 - * This program is free software: you can redistribute it and/or modify
24.9 - * it under the terms of the GNU General Public License as published by
24.10 - * the Free Software Foundation, either version 3 of the License, or
24.11 - * (at your option) any later version.
24.12 - *
24.13 - * This program is distributed in the hope that it will be useful,
24.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
24.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24.16 - * GNU General Public License for more details.
24.17 - *
24.18 - * You should have received a copy of the GNU General Public License
24.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
24.20 - */
24.21 -package info.globalcode.sql.dk;
24.22 -
24.23 -import info.globalcode.sql.dk.configuration.NameIdentified;
24.24 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
24.25 -import info.globalcode.sql.dk.configuration.PropertyDeclarations;
24.26 -import info.globalcode.sql.dk.formatting.Formatter;
24.27 -import java.io.BufferedReader;
24.28 -import java.io.File;
24.29 -import java.io.IOException;
24.30 -import java.io.InputStream;
24.31 -import java.io.InputStreamReader;
24.32 -import java.io.PrintWriter;
24.33 -import java.util.ArrayList;
24.34 -import java.util.Arrays;
24.35 -import java.util.Collection;
24.36 -import java.util.Collections;
24.37 -import java.util.List;
24.38 -import java.util.Map;
24.39 -import java.util.regex.Matcher;
24.40 -import java.util.regex.Pattern;
24.41 -
24.42 -/**
24.43 - *
24.44 - * @author Ing. František Kučera (frantovo.cz)
24.45 - */
24.46 -public class Functions {
24.47 -
24.48 - private static final String NBSP = " ";
24.49 - private static final Pattern WHITESPACE_TO_REPLACE = Pattern.compile("\\n|\\r|\\t|" + NBSP);
24.50 -
24.51 - private Functions() {
24.52 - }
24.53 -
24.54 - public static boolean equalz(Object a, Object b) {
24.55 - return a == null ? b == null : a.equals(b);
24.56 - }
24.57 -
24.58 - /**
24.59 - *
24.60 - * @param text String to be examinated
24.61 - * @param trim whether text should be trimmed before examination
24.62 - * @return whether text is not empty and one or more characters long (after prospective trim)
24.63 - */
24.64 - public static boolean isEmpty(String text, boolean trim) {
24.65 - if (text == null) {
24.66 - return true;
24.67 - } else {
24.68 - if (trim) {
24.69 - text = text.trim();
24.70 - }
24.71 - return text.isEmpty();
24.72 - }
24.73 - }
24.74 -
24.75 - /**
24.76 - * @see #isEmpty(java.lang.String, boolean)
24.77 - */
24.78 - public static boolean isNotEmpty(String text, boolean trim) {
24.79 - return !isEmpty(text, trim);
24.80 - }
24.81 -
24.82 - public boolean isEmpty(Collection c) {
24.83 - return c == null || c.isEmpty();
24.84 - }
24.85 -
24.86 - public boolean isNotEmpty(Collection c) {
24.87 - return !isEmpty(c);
24.88 - }
24.89 -
24.90 - public boolean isEmpty(Map m) {
24.91 - return m == null || m.isEmpty();
24.92 - }
24.93 -
24.94 - public boolean isNotEmpty(Map m) {
24.95 - return !isEmpty(m);
24.96 - }
24.97 -
24.98 - /**
24.99 - * @return empty collection if given one is null | or the original one
24.100 - */
24.101 - public static <T> Collection<T> notNull(Collection<T> c) {
24.102 - if (c == null) {
24.103 - return Collections.emptyList();
24.104 - } else {
24.105 - return c;
24.106 - }
24.107 - }
24.108 -
24.109 - public static <T extends NameIdentified> T findByName(Collection<T> collection, String name) {
24.110 - for (T element : notNull(collection)) {
24.111 - if (element != null && equalz(element.getName(), name)) {
24.112 - return element;
24.113 - }
24.114 - }
24.115 -
24.116 - return null;
24.117 - }
24.118 -
24.119 - /**
24.120 - * Copy file from Java resources to file system.
24.121 - */
24.122 - public static void installResource(String resourceName, File target) throws IOException {
24.123 - try (BufferedReader reader = new BufferedReader(new InputStreamReader(Functions.class.getClassLoader().getResourceAsStream(resourceName)))) {
24.124 - try (PrintWriter writer = new PrintWriter(target)) {
24.125 - while (true) {
24.126 - String line = reader.readLine();
24.127 - if (line == null) {
24.128 - break;
24.129 - } else {
24.130 - writer.println(line);
24.131 - }
24.132 - }
24.133 - }
24.134 - }
24.135 - }
24.136 -
24.137 - public static String rpad(String s, int n) {
24.138 - if (n > 0) {
24.139 - return String.format("%1$-" + n + "s", s);
24.140 - } else {
24.141 - return s;
24.142 - }
24.143 - }
24.144 -
24.145 - public static String lpad(String s, int n) {
24.146 - if (n > 0) {
24.147 - return String.format("%1$" + n + "s", s);
24.148 - } else {
24.149 - return s;
24.150 - }
24.151 - }
24.152 -
24.153 - public static String repeat(char ch, int count) {
24.154 - char[] array = new char[count];
24.155 - Arrays.fill(array, ch);
24.156 - return new String(array);
24.157 - }
24.158 - private final static char[] HEX_ALPHABET = "0123456789abcdef".toCharArray();
24.159 -
24.160 - public static String toHex(byte[] bytes) {
24.161 - char[] hexChars = new char[bytes.length * 2];
24.162 - for (int j = 0; j < bytes.length; j++) {
24.163 - int v = bytes[j] & 0xFF;
24.164 - hexChars[j * 2] = HEX_ALPHABET[v >>> 4];
24.165 - hexChars[j * 2 + 1] = HEX_ALPHABET[v & 0x0F];
24.166 - }
24.167 - return new String(hexChars);
24.168 - }
24.169 -
24.170 - public static String readString(InputStream in) throws IOException {
24.171 - try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
24.172 - StringBuilder result = new StringBuilder();
24.173 - for (String line = br.readLine(); line != null; line = br.readLine()) {
24.174 - result.append(line);
24.175 - result.append('\n');
24.176 - }
24.177 - return result.toString();
24.178 - }
24.179 - }
24.180 -
24.181 - /**
24.182 - * @param <P> type of the last parent
24.183 - * @param <T> type of the examined class
24.184 - * @param type examined class
24.185 - * @param lastParent the last parent type to stop at
24.186 - * @return list of types starting with <code>type</code> and ending with <code>lastParent</code>
24.187 - */
24.188 - public static <P, T extends P> List<Class<? extends P>> getClassHierarchy(Class<T> type, Class<P> lastParent) {
24.189 - List<Class<? extends P>> hierarchy = new ArrayList<>();
24.190 -
24.191 - for (Class current = type; current != null && lastParent.isAssignableFrom(current); current = current.getSuperclass()) {
24.192 - hierarchy.add(current);
24.193 - }
24.194 -
24.195 - return hierarchy;
24.196 - }
24.197 -
24.198 - public static PropertyDeclaration[] getPropertyDeclarations(Class<? extends Formatter> formatterClass) {
24.199 - PropertyDeclarations properties = formatterClass.getAnnotation(PropertyDeclarations.class);
24.200 -
24.201 - if (properties == null) {
24.202 - PropertyDeclaration p = formatterClass.getAnnotation(PropertyDeclaration.class);
24.203 - return p == null ? new PropertyDeclaration[]{} : new PropertyDeclaration[]{p};
24.204 - } else {
24.205 - return properties.value();
24.206 - }
24.207 - }
24.208 -
24.209 - /**
24.210 - * TODO: support background or styles and move to ColorfulPrintWriter
24.211 - *
24.212 - * @param out
24.213 - * @param valueString
24.214 - * @param basicColor
24.215 - * @param escapeColor
24.216 - */
24.217 - public static void printValueWithWhitespaceReplaced(ColorfulPrintWriter out, String valueString, ColorfulPrintWriter.TerminalColor basicColor, ColorfulPrintWriter.TerminalColor escapeColor) {
24.218 -
24.219 - Matcher m = WHITESPACE_TO_REPLACE.matcher(valueString);
24.220 -
24.221 - int start = 0;
24.222 -
24.223 - while (m.find(start)) {
24.224 -
24.225 - printColorOrNot(out, basicColor, valueString.substring(start, m.start()));
24.226 -
24.227 - switch (m.group()) {
24.228 - case "\n":
24.229 - out.print(escapeColor, "↲");
24.230 - break;
24.231 - case "\r":
24.232 - out.print(escapeColor, "⏎");
24.233 - break;
24.234 - case "\t":
24.235 - out.print(escapeColor, "↹");
24.236 - break;
24.237 - case NBSP:
24.238 - out.print(escapeColor, "⎵");
24.239 - break;
24.240 - default:
24.241 - throw new IllegalStateException("Unexpected whitespace token: „" + m.group() + "“");
24.242 - }
24.243 -
24.244 - start = m.end();
24.245 - }
24.246 -
24.247 - printColorOrNot(out, basicColor, valueString.substring(start, valueString.length()));
24.248 - }
24.249 -
24.250 - private static void printColorOrNot(ColorfulPrintWriter out, ColorfulPrintWriter.TerminalColor color, String text) {
24.251 - if (color == null) {
24.252 - out.print(text);
24.253 - } else {
24.254 - out.print(color, text);
24.255 - }
24.256 - }
24.257 -}
25.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java Mon Mar 04 17:06:42 2019 +0100
25.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
25.3 @@ -1,673 +0,0 @@
25.4 -/**
25.5 - * SQL-DK
25.6 - * Copyright © 2013 František Kučera (frantovo.cz)
25.7 - *
25.8 - * This program is free software: you can redistribute it and/or modify
25.9 - * it under the terms of the GNU General Public License as published by
25.10 - * the Free Software Foundation, either version 3 of the License, or
25.11 - * (at your option) any later version.
25.12 - *
25.13 - * This program is distributed in the hope that it will be useful,
25.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
25.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25.16 - * GNU General Public License for more details.
25.17 - *
25.18 - * You should have received a copy of the GNU General Public License
25.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
25.20 - */
25.21 -package info.globalcode.sql.dk;
25.22 -
25.23 -import info.globalcode.sql.dk.configuration.CommandArgument;
25.24 -import info.globalcode.sql.dk.configuration.Configuration;
25.25 -import info.globalcode.sql.dk.configuration.ConfigurationException;
25.26 -import info.globalcode.sql.dk.configuration.ConfigurationProvider;
25.27 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
25.28 -import info.globalcode.sql.dk.configuration.FormatterDefinition;
25.29 -import info.globalcode.sql.dk.configuration.Properties;
25.30 -import info.globalcode.sql.dk.configuration.Property;
25.31 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
25.32 -import info.globalcode.sql.dk.configuration.TunnelDefinition;
25.33 -import info.globalcode.sql.dk.formatting.ColumnsHeader;
25.34 -import info.globalcode.sql.dk.formatting.CommonProperties;
25.35 -import info.globalcode.sql.dk.formatting.FakeSqlArray;
25.36 -import info.globalcode.sql.dk.formatting.Formatter;
25.37 -import info.globalcode.sql.dk.formatting.FormatterContext;
25.38 -import info.globalcode.sql.dk.formatting.FormatterException;
25.39 -import java.io.BufferedReader;
25.40 -import java.io.ByteArrayOutputStream;
25.41 -import java.io.InputStreamReader;
25.42 -import java.io.PrintStream;
25.43 -import java.sql.Array;
25.44 -import java.sql.Driver;
25.45 -import java.sql.DriverManager;
25.46 -import java.sql.DriverPropertyInfo;
25.47 -import java.sql.SQLException;
25.48 -import java.util.ArrayList;
25.49 -import java.util.Collections;
25.50 -import java.util.Comparator;
25.51 -import java.util.EnumSet;
25.52 -import java.util.HashMap;
25.53 -import java.util.HashSet;
25.54 -import java.util.List;
25.55 -import java.util.Map;
25.56 -import java.util.Map.Entry;
25.57 -import java.util.ServiceLoader;
25.58 -import java.util.Set;
25.59 -import java.util.concurrent.ExecutorService;
25.60 -import java.util.concurrent.Executors;
25.61 -import java.util.concurrent.TimeUnit;
25.62 -import java.util.logging.Level;
25.63 -import java.util.logging.LogRecord;
25.64 -import java.util.logging.Logger;
25.65 -import javax.sql.rowset.RowSetMetaDataImpl;
25.66 -
25.67 -/**
25.68 - * Displays info like help, version etc.
25.69 - *
25.70 - * @author Ing. František Kučera (frantovo.cz)
25.71 - */
25.72 -public class InfoLister {
25.73 -
25.74 - private static final Logger log = Logger.getLogger(InfoLister.class.getName());
25.75 - /**
25.76 - * Fake database name for output formatting
25.77 - */
25.78 - public static final String CONFIG_DB_NAME = "sqldk_configuration";
25.79 - private final PrintStream out;
25.80 - private final ConfigurationProvider configurationProvider;
25.81 - private final CLIOptions options;
25.82 - private Formatter formatter;
25.83 -
25.84 - public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
25.85 - this.out = out;
25.86 - this.configurationProvider = configurationProvider;
25.87 - this.options = options;
25.88 - }
25.89 -
25.90 - public void showInfo() throws ConfigurationException, FormatterException {
25.91 - EnumSet<InfoType> commands = options.getShowInfo();
25.92 -
25.93 - boolean formattinNeeded = false;
25.94 -
25.95 - for (InfoType infoType : commands) {
25.96 - switch (infoType) {
25.97 - case CONNECTION:
25.98 - case JDBC_DRIVERS:
25.99 - case JDBC_PROPERTIES:
25.100 - case DATABASES:
25.101 - case FORMATTERS:
25.102 - case FORMATTER_PROPERTIES:
25.103 - case TYPES:
25.104 - case JAVA_PROPERTIES:
25.105 - case ENVIRONMENT_VARIABLES:
25.106 - formattinNeeded = true;
25.107 - break;
25.108 - }
25.109 - }
25.110 -
25.111 - if (formattinNeeded) {
25.112 - try (Formatter f = getFormatter()) {
25.113 - formatter = f;
25.114 - formatter.writeStartBatch();
25.115 - DatabaseDefinition dd = new DatabaseDefinition();
25.116 - dd.setName(CONFIG_DB_NAME);
25.117 - formatter.writeStartDatabase(dd);
25.118 - showInfos(commands);
25.119 - formatter.writeEndDatabase();
25.120 - formatter.writeEndBatch();
25.121 - formatter.close();
25.122 - }
25.123 - } else {
25.124 - showInfos(commands);
25.125 - }
25.126 - }
25.127 -
25.128 - private void showInfos(EnumSet<InfoType> commands) throws ConfigurationException, FormatterException {
25.129 - for (InfoType infoType : commands) {
25.130 - infoType.showInfo(this);
25.131 - }
25.132 - }
25.133 -
25.134 - private void listJavaProperties() throws FormatterException, ConfigurationException {
25.135 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
25.136 - List<Object[]> data = new ArrayList<>();
25.137 - for (Entry<Object, Object> e : System.getProperties().entrySet()) {
25.138 - data.add(new Object[]{e.getKey(), e.getValue()});
25.139 - }
25.140 - printTable(formatter, header, "-- Java system properties", null, data, 0);
25.141 - }
25.142 -
25.143 - private void listEnvironmentVariables() throws FormatterException, ConfigurationException {
25.144 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
25.145 - List<Object[]> data = new ArrayList<>();
25.146 - for (Entry<String, String> e : System.getenv().entrySet()) {
25.147 - data.add(new Object[]{e.getKey(), e.getValue()});
25.148 - }
25.149 - printTable(formatter, header, "-- environment variables", null, data, 0);
25.150 - }
25.151 -
25.152 - private void listFormatters() throws ConfigurationException, FormatterException {
25.153 - ColumnsHeader header = constructHeader(
25.154 - new HeaderField("name", SQLType.VARCHAR),
25.155 - new HeaderField("built_in", SQLType.BOOLEAN),
25.156 - new HeaderField("default", SQLType.BOOLEAN),
25.157 - new HeaderField("class_name", SQLType.VARCHAR),
25.158 - new HeaderField("valid", SQLType.BOOLEAN));
25.159 - List<Object[]> data = new ArrayList<>();
25.160 -
25.161 - String defaultFormatter = configurationProvider.getConfiguration().getDefaultFormatter();
25.162 - defaultFormatter = defaultFormatter == null ? Configuration.DEFAULT_FORMATTER : defaultFormatter;
25.163 -
25.164 - for (FormatterDefinition fd : configurationProvider.getConfiguration().getBuildInFormatters()) {
25.165 - data.add(new Object[]{fd.getName(), true, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
25.166 - }
25.167 -
25.168 - for (FormatterDefinition fd : configurationProvider.getConfiguration().getFormatters()) {
25.169 - data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
25.170 - }
25.171 -
25.172 - printTable(formatter, header, "-- configured and built-in output formatters", null, data);
25.173 - }
25.174 -
25.175 - private boolean isInstantiable(FormatterDefinition fd) {
25.176 - try {
25.177 - try (ByteArrayOutputStream testStream = new ByteArrayOutputStream()) {
25.178 - fd.getInstance(new FormatterContext(testStream, new Properties(0)));
25.179 - return true;
25.180 - }
25.181 - } catch (Exception e) {
25.182 - log.log(Level.SEVERE, "Unable to create an instance of formatter: " + fd.getName(), e);
25.183 - return false;
25.184 - }
25.185 - }
25.186 -
25.187 - private void listFormatterProperties() throws FormatterException, ConfigurationException {
25.188 - for (String formatterName : options.getFormatterNamesToListProperties()) {
25.189 - listFormatterProperties(formatterName);
25.190 - }
25.191 - }
25.192 -
25.193 - private void listFormatterProperties(String formatterName) throws FormatterException, ConfigurationException {
25.194 - FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
25.195 - try {
25.196 -
25.197 - // currently only for debugging purposes
25.198 - // TODO: introduce --info-lister-property or generic filtering capability in printTable() ?
25.199 - boolean printDeclaredIn = options.getFormatterProperties().getBoolean("InfoLister:print:declared_in", false);
25.200 -
25.201 - List<HeaderField> headerFields = new ArrayList<>();
25.202 - headerFields.add(new HeaderField("name", SQLType.VARCHAR));
25.203 - headerFields.add(new HeaderField("type", SQLType.VARCHAR));
25.204 - headerFields.add(new HeaderField("default", SQLType.VARCHAR));
25.205 - headerFields.add(new HeaderField("description", SQLType.VARCHAR));
25.206 - if (printDeclaredIn) {
25.207 - headerFields.add(new HeaderField("declared_in", SQLType.VARCHAR));
25.208 - }
25.209 -
25.210 - ColumnsHeader header = constructHeader(headerFields.toArray(new HeaderField[0]));
25.211 -
25.212 - Map<String, Object[]> data = new HashMap<>();
25.213 - Class<Formatter> formatterClass = (Class<Formatter>) Class.forName(fd.getClassName());
25.214 - List<Class<? extends Formatter>> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class);
25.215 - Collections.reverse(hierarchy);
25.216 - hierarchy.stream().forEach((c) -> {
25.217 - for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) {
25.218 - data.put(p.name(), propertyDeclarationToRow(p, c, printDeclaredIn));
25.219 - }
25.220 - });
25.221 -
25.222 - List<Parameter> parameters = new ArrayList<>();
25.223 - parameters.add(new NamedParameter("formatter", formatterName, SQLType.VARCHAR));
25.224 -
25.225 - printTable(formatter, header, "-- formatter properties", parameters, new ArrayList<>(data.values()));
25.226 - } catch (ClassNotFoundException e) {
25.227 - throw new ConfigurationException("Unable to find class " + fd.getClassName() + " of formatter" + fd.getName(), e);
25.228 - }
25.229 - }
25.230 -
25.231 - private static Object[] propertyDeclarationToRow(PropertyDeclaration p, Class formatterClass, boolean printDeclaredIn) {
25.232 - List list = new ArrayList();
25.233 -
25.234 - list.add(p.name());
25.235 - list.add(CommonProperties.getSimpleTypeName(p.type()));
25.236 - list.add(p.defaultValue());
25.237 - list.add(p.description());
25.238 - if (printDeclaredIn) {
25.239 - list.add(formatterClass.getName());
25.240 - }
25.241 -
25.242 - return list.toArray();
25.243 - }
25.244 -
25.245 - private void listTypes() throws FormatterException, ConfigurationException {
25.246 - ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("code", SQLType.INTEGER));
25.247 - List<Object[]> data = new ArrayList<>();
25.248 - for (SQLType sqlType : SQLType.values()) {
25.249 - data.add(new Object[]{sqlType.name(), sqlType.getCode()});
25.250 - }
25.251 - printTable(formatter, header, "-- data types", null, data);
25.252 - log.log(Level.INFO, "Type names in --types option are case insensitive");
25.253 - }
25.254 -
25.255 - private void listDatabases() throws ConfigurationException, FormatterException {
25.256 - ColumnsHeader header = constructHeader(
25.257 - new HeaderField("database_name", SQLType.VARCHAR),
25.258 - new HeaderField("user_name", SQLType.VARCHAR),
25.259 - new HeaderField("database_url", SQLType.VARCHAR));
25.260 - List<Object[]> data = new ArrayList<>();
25.261 -
25.262 - final List<DatabaseDefinition> configuredDatabases = configurationProvider.getConfiguration().getDatabases();
25.263 - if (configuredDatabases.isEmpty()) {
25.264 - log.log(Level.WARNING, "No databases are configured.");
25.265 - } else {
25.266 - for (DatabaseDefinition dd : configuredDatabases) {
25.267 - data.add(new Object[]{dd.getName(), dd.getUserName(), dd.getUrl()});
25.268 -
25.269 - final TunnelDefinition tunnel = dd.getTunnel();
25.270 - if (tunnel != null) {
25.271 - log.log(Level.INFO, "Tunnel command: {0}", tunnel.getCommand());
25.272 - for (CommandArgument ca : Functions.notNull(tunnel.getArguments())) {
25.273 - log.log(Level.INFO, "\targument: {0}/{1}", new Object[]{ca.getType(), ca.getValue()});
25.274 - }
25.275 - }
25.276 -
25.277 - }
25.278 - }
25.279 -
25.280 - printTable(formatter, header, "-- configured databases", null, data);
25.281 - }
25.282 -
25.283 - private void listJdbcDrivers() throws FormatterException, ConfigurationException {
25.284 - ColumnsHeader header = constructHeader(
25.285 - new HeaderField("class", SQLType.VARCHAR),
25.286 - new HeaderField("version", SQLType.VARCHAR),
25.287 - new HeaderField("major", SQLType.INTEGER),
25.288 - new HeaderField("minor", SQLType.INTEGER),
25.289 - new HeaderField("jdbc_compliant", SQLType.BOOLEAN));
25.290 - List<Object[]> data = new ArrayList<>();
25.291 -
25.292 - final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
25.293 - for (Driver d : drivers) {
25.294 - data.add(new Object[]{
25.295 - d.getClass().getName(),
25.296 - d.getMajorVersion() + "." + d.getMinorVersion(),
25.297 - d.getMajorVersion(),
25.298 - d.getMinorVersion(),
25.299 - d.jdbcCompliant()
25.300 - });
25.301 - }
25.302 -
25.303 - printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
25.304 - }
25.305 -
25.306 - private void listJdbcProperties() throws FormatterException, ConfigurationException {
25.307 - for (String dbName : options.getDatabaseNamesToListProperties()) {
25.308 - ColumnsHeader header = constructHeader(
25.309 - new HeaderField("property_name", SQLType.VARCHAR),
25.310 - new HeaderField("required", SQLType.BOOLEAN),
25.311 - new HeaderField("choices", SQLType.ARRAY),
25.312 - new HeaderField("configured_value", SQLType.VARCHAR),
25.313 - new HeaderField("description", SQLType.VARCHAR));
25.314 - List<Object[]> data = new ArrayList<>();
25.315 -
25.316 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
25.317 -
25.318 - Driver driver = findDriver(dd);
25.319 -
25.320 - if (driver == null) {
25.321 - log.log(Level.WARNING, "No JDBC driver was found for DB: {0} with URL: {1}", new Object[]{dd.getName(), dd.getUrl()});
25.322 - } else {
25.323 - log.log(Level.INFO, "For DB: {0} was found JDBC driver: {1}", new Object[]{dd.getName(), driver.getClass().getName()});
25.324 -
25.325 - try {
25.326 - DriverPropertyInfo[] propertyInfos = driver.getPropertyInfo(dd.getUrl(), dd.getProperties().getJavaProperties());
25.327 -
25.328 - Set<String> standardProperties = new HashSet<>();
25.329 -
25.330 - for (DriverPropertyInfo pi : propertyInfos) {
25.331 - Array choices = new FakeSqlArray(pi.choices, SQLType.VARCHAR);
25.332 - data.add(new Object[]{
25.333 - pi.name,
25.334 - pi.required,
25.335 - choices.getArray() == null ? "" : choices,
25.336 - pi.value == null ? "" : pi.value,
25.337 - pi.description
25.338 - });
25.339 - standardProperties.add(pi.name);
25.340 - }
25.341 -
25.342 - for (Property p : dd.getProperties()) {
25.343 - if (!standardProperties.contains(p.getName())) {
25.344 - data.add(new Object[]{
25.345 - p.getName(),
25.346 - "",
25.347 - "",
25.348 - p.getValue(),
25.349 - ""
25.350 - });
25.351 - log.log(Level.WARNING, "Your configuration contains property „{0}“ not declared by the JDBC driver.", p.getName());
25.352 - }
25.353 - }
25.354 -
25.355 - } catch (SQLException e) {
25.356 - log.log(Level.WARNING, "Error during getting property infos.", e);
25.357 - }
25.358 -
25.359 - List<Parameter> parameters = new ArrayList<>();
25.360 - parameters.add(new NamedParameter("database", dbName, SQLType.VARCHAR));
25.361 - parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
25.362 - parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
25.363 - parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
25.364 -
25.365 - printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
25.366 - }
25.367 - }
25.368 -
25.369 - }
25.370 -
25.371 - private Driver findDriver(DatabaseDefinition dd) {
25.372 - final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
25.373 - for (Driver d : drivers) {
25.374 - try {
25.375 - if (d.acceptsURL(dd.getUrl())) {
25.376 - return d;
25.377 - }
25.378 - } catch (SQLException e) {
25.379 - log.log(Level.WARNING, "Error during finding JDBC driver for: " + dd.getName(), e);
25.380 - }
25.381 - }
25.382 - return null;
25.383 - }
25.384 -
25.385 - /**
25.386 - * Parallelism for connection testing – maximum concurrent database connections.
25.387 - */
25.388 - private static final int TESTING_THREAD_COUNT = 64;
25.389 - /**
25.390 - * Time limit for all connection testing threads – particular timeouts per connection will be
25.391 - * much smaller.
25.392 - */
25.393 - private static final long TESTING_AWAIT_LIMIT = 1;
25.394 - private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
25.395 -
25.396 - private void testConnections() throws FormatterException, ConfigurationException {
25.397 - ColumnsHeader header = constructHeader(
25.398 - new HeaderField("database_name", SQLType.VARCHAR),
25.399 - new HeaderField("configured", SQLType.BOOLEAN),
25.400 - new HeaderField("connected", SQLType.BOOLEAN),
25.401 - new HeaderField("product_name", SQLType.VARCHAR),
25.402 - new HeaderField("product_version", SQLType.VARCHAR));
25.403 -
25.404 - log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
25.405 -
25.406 - ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
25.407 -
25.408 - final Formatter currentFormatter = formatter;
25.409 -
25.410 - printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
25.411 -
25.412 - for (final String dbName : options.getDatabaseNamesToTest()) {
25.413 - preloadDriver(dbName);
25.414 - }
25.415 -
25.416 - for (final String dbName : options.getDatabaseNamesToTest()) {
25.417 - es.submit(() -> {
25.418 - final Object[] row = testConnection(dbName);
25.419 - synchronized (currentFormatter) {
25.420 - printRow(currentFormatter, row);
25.421 - }
25.422 - }
25.423 - );
25.424 - }
25.425 -
25.426 - es.shutdown();
25.427 -
25.428 - try {
25.429 - log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
25.430 - boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
25.431 - if (finished) {
25.432 - log.log(Level.FINEST, "All testing threads finished in time limit.");
25.433 - } else {
25.434 - throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
25.435 - }
25.436 - } catch (InterruptedException e) {
25.437 - throw new FormatterException("Interrupted while waiting for test results", e);
25.438 - }
25.439 -
25.440 - printFooter(currentFormatter);
25.441 - }
25.442 -
25.443 - /**
25.444 - * JDBC driver classes should be preloaded in single thread to avoid deadlocks while doing
25.445 - * {@linkplain DriverManager#registerDriver(java.sql.Driver)} during parallel connections.
25.446 - *
25.447 - * @param dbName
25.448 - */
25.449 - private void preloadDriver(String dbName) {
25.450 - try {
25.451 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
25.452 - Driver driver = findDriver(dd);
25.453 - if (driver == null) {
25.454 - log.log(Level.WARNING, "No Driver found for DB: {0}", dbName);
25.455 - } else {
25.456 - log.log(Level.FINEST, "Driver preloading for DB: {0} was successfull", dbName);
25.457 - }
25.458 - } catch (Exception e) {
25.459 - LogRecord r = new LogRecord(Level.WARNING, "Failed to preload the Driver for DB: {0}");
25.460 - r.setParameters(new Object[]{dbName});
25.461 - r.setThrown(e);
25.462 - log.log(r);
25.463 - }
25.464 - }
25.465 -
25.466 - private Object[] testConnection(String dbName) {
25.467 - log.log(Level.FINE, "Testing connection to database: {0}", dbName);
25.468 -
25.469 - boolean succesfullyConnected = false;
25.470 - boolean succesfullyConfigured = false;
25.471 - String productName = null;
25.472 - String productVersion = null;
25.473 -
25.474 - try {
25.475 - DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
25.476 - log.log(Level.FINE, "Database definition was loaded from configuration");
25.477 - succesfullyConfigured = true;
25.478 - try (DatabaseConnection dc = dd.connect(options.getDatabaseProperties())) {
25.479 - succesfullyConnected = dc.test();
25.480 - productName = dc.getProductName();
25.481 - productVersion = dc.getProductVersion();
25.482 - }
25.483 - log.log(Level.FINE, "Database connection test was successful");
25.484 - } catch (ConfigurationException | SQLException | RuntimeException e) {
25.485 - log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
25.486 - }
25.487 -
25.488 - return new Object[]{dbName, succesfullyConfigured, succesfullyConnected, productName, productVersion};
25.489 - }
25.490 -
25.491 - private void printResource(String fileName) {
25.492 - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName)))) {
25.493 - while (true) {
25.494 - String line = reader.readLine();
25.495 - if (line == null) {
25.496 - break;
25.497 - } else {
25.498 - println(line);
25.499 - }
25.500 - }
25.501 - } catch (Exception e) {
25.502 - log.log(Level.SEVERE, "Unable to print this info. Please see our website for it: " + Constants.WEBSITE, e);
25.503 - }
25.504 - }
25.505 -
25.506 - private void println(String line) {
25.507 - out.println(line);
25.508 - }
25.509 -
25.510 - private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
25.511 - printTable(formatter, header, sql, parameters, data, null);
25.512 - }
25.513 -
25.514 - private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data, final Integer sortByColumn) throws ConfigurationException, FormatterException {
25.515 - printHeader(formatter, header, sql, parameters);
25.516 -
25.517 - if (sortByColumn != null) {
25.518 - Collections.sort(data, new Comparator<Object[]>() {
25.519 -
25.520 - @Override
25.521 - public int compare(Object[] o1, Object[] o2) {
25.522 - String s1 = String.valueOf(o1[sortByColumn]);
25.523 - String s2 = String.valueOf(o2[sortByColumn]);
25.524 - return s1.compareTo(s2);
25.525 - }
25.526 - });
25.527 - }
25.528 -
25.529 - for (Object[] row : data) {
25.530 - printRow(formatter, row);
25.531 - }
25.532 -
25.533 - printFooter(formatter);
25.534 - }
25.535 -
25.536 - private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
25.537 - formatter.writeStartStatement();
25.538 - if (sql != null) {
25.539 - formatter.writeQuery(sql);
25.540 - if (parameters != null) {
25.541 - formatter.writeParameters(parameters);
25.542 - }
25.543 - }
25.544 - formatter.writeStartResultSet(header);
25.545 - }
25.546 -
25.547 - private void printRow(Formatter formatter, Object[] row) {
25.548 - formatter.writeStartRow();
25.549 - for (Object cell : row) {
25.550 - formatter.writeColumnValue(cell);
25.551 - }
25.552 - formatter.writeEndRow();
25.553 - }
25.554 -
25.555 - private void printFooter(Formatter formatter) {
25.556 - formatter.writeEndResultSet();
25.557 - formatter.writeEndStatement();
25.558 - }
25.559 -
25.560 - private Formatter getFormatter() throws ConfigurationException, FormatterException {
25.561 - String formatterName = options.getFormatterName();
25.562 - formatterName = formatterName == null ? Configuration.DEFAULT_FORMATTER_PREFETCHING : formatterName;
25.563 - FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
25.564 - FormatterContext context = new FormatterContext(out, options.getFormatterProperties());
25.565 - return fd.getInstance(context);
25.566 - }
25.567 -
25.568 - private ColumnsHeader constructHeader(HeaderField... fields) throws FormatterException {
25.569 - try {
25.570 - RowSetMetaDataImpl metaData = new RowSetMetaDataImpl();
25.571 - metaData.setColumnCount(fields.length);
25.572 -
25.573 - for (int i = 0; i < fields.length; i++) {
25.574 - HeaderField hf = fields[i];
25.575 - int sqlIndex = i + 1;
25.576 - metaData.setColumnName(sqlIndex, hf.name);
25.577 - metaData.setColumnLabel(sqlIndex, hf.name);
25.578 - metaData.setColumnType(sqlIndex, hf.type.getCode());
25.579 - metaData.setColumnTypeName(sqlIndex, hf.type.name());
25.580 - }
25.581 -
25.582 - return new ColumnsHeader(metaData);
25.583 - } catch (SQLException e) {
25.584 - throw new FormatterException("Error while constructing table headers", e);
25.585 - }
25.586 - }
25.587 -
25.588 - private static class HeaderField {
25.589 -
25.590 - String name;
25.591 - SQLType type;
25.592 -
25.593 - public HeaderField(String name, SQLType type) {
25.594 - this.name = name;
25.595 - this.type = type;
25.596 - }
25.597 - }
25.598 -
25.599 - public enum InfoType {
25.600 -
25.601 - HELP {
25.602 - @Override
25.603 - public void showInfo(InfoLister infoLister) {
25.604 - infoLister.printResource(Constants.HELP_FILE);
25.605 - }
25.606 - },
25.607 - VERSION {
25.608 - @Override
25.609 - public void showInfo(InfoLister infoLister) {
25.610 - infoLister.printResource(Constants.VERSION_FILE);
25.611 - }
25.612 - },
25.613 - LICENSE {
25.614 - @Override
25.615 - public void showInfo(InfoLister infoLister) {
25.616 - infoLister.printResource(Constants.LICENSE_FILE);
25.617 - }
25.618 - },
25.619 - JAVA_PROPERTIES {
25.620 - @Override
25.621 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.622 - infoLister.listJavaProperties();
25.623 - }
25.624 - },
25.625 - ENVIRONMENT_VARIABLES {
25.626 - @Override
25.627 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.628 - infoLister.listEnvironmentVariables();
25.629 - }
25.630 - },
25.631 - FORMATTERS {
25.632 - @Override
25.633 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.634 - infoLister.listFormatters();
25.635 - }
25.636 - },
25.637 - FORMATTER_PROPERTIES {
25.638 - @Override
25.639 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.640 - infoLister.listFormatterProperties();
25.641 - }
25.642 - },
25.643 - TYPES {
25.644 - @Override
25.645 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.646 - infoLister.listTypes();
25.647 - }
25.648 - },
25.649 - JDBC_DRIVERS {
25.650 - @Override
25.651 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
25.652 - infoLister.listJdbcDrivers();
25.653 - }
25.654 - },
25.655 - JDBC_PROPERTIES {
25.656 - @Override
25.657 - public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
25.658 - infoLister.listJdbcProperties();
25.659 - }
25.660 - },
25.661 - DATABASES {
25.662 - @Override
25.663 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.664 - infoLister.listDatabases();
25.665 - }
25.666 - },
25.667 - CONNECTION {
25.668 - @Override
25.669 - public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
25.670 - infoLister.testConnections();
25.671 - }
25.672 - };
25.673 -
25.674 - public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
25.675 - }
25.676 -}
26.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InvalidOptionsException.java Mon Mar 04 17:06:42 2019 +0100
26.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
26.3 @@ -1,66 +0,0 @@
26.4 -/**
26.5 - * SQL-DK
26.6 - * Copyright © 2013 František Kučera (frantovo.cz)
26.7 - *
26.8 - * This program is free software: you can redistribute it and/or modify
26.9 - * it under the terms of the GNU General Public License as published by
26.10 - * the Free Software Foundation, either version 3 of the License, or
26.11 - * (at your option) any later version.
26.12 - *
26.13 - * This program is distributed in the hope that it will be useful,
26.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
26.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26.16 - * GNU General Public License for more details.
26.17 - *
26.18 - * You should have received a copy of the GNU General Public License
26.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
26.20 - */
26.21 -package info.globalcode.sql.dk;
26.22 -
26.23 -import java.util.ArrayList;
26.24 -import java.util.Collection;
26.25 -import java.util.Collections;
26.26 -
26.27 -/**
26.28 - *
26.29 - * @author Ing. František Kučera (frantovo.cz)
26.30 - */
26.31 -public class InvalidOptionsException extends Exception {
26.32 -
26.33 - private final Collection<OptionProblem> problems = new ArrayList<>();
26.34 -
26.35 - public Collection<OptionProblem> getProblems() {
26.36 - return Collections.unmodifiableCollection(problems);
26.37 - }
26.38 -
26.39 - public void addProblem(OptionProblem p) {
26.40 - problems.add(p);
26.41 - }
26.42 -
26.43 - public boolean hasProblems() {
26.44 - return !problems.isEmpty();
26.45 - }
26.46 -
26.47 - public static class OptionProblem {
26.48 -
26.49 - private String description;
26.50 - private Throwable exception;
26.51 -
26.52 - public OptionProblem(String description) {
26.53 - this.description = description;
26.54 - }
26.55 -
26.56 - public OptionProblem(String description, Throwable exception) {
26.57 - this.description = description;
26.58 - this.exception = exception;
26.59 - }
26.60 -
26.61 - public String getDescription() {
26.62 - return description;
26.63 - }
26.64 -
26.65 - public Throwable getException() {
26.66 - return exception;
26.67 - }
26.68 - }
26.69 -}
27.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/NamedParameter.java Mon Mar 04 17:06:42 2019 +0100
27.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
27.3 @@ -1,48 +0,0 @@
27.4 -/**
27.5 - * SQL-DK
27.6 - * Copyright © 2013 František Kučera (frantovo.cz)
27.7 - *
27.8 - * This program is free software: you can redistribute it and/or modify
27.9 - * it under the terms of the GNU General Public License as published by
27.10 - * the Free Software Foundation, either version 3 of the License, or
27.11 - * (at your option) any later version.
27.12 - *
27.13 - * This program is distributed in the hope that it will be useful,
27.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.16 - * GNU General Public License for more details.
27.17 - *
27.18 - * You should have received a copy of the GNU General Public License
27.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
27.20 - */
27.21 -package info.globalcode.sql.dk;
27.22 -
27.23 -import info.globalcode.sql.dk.configuration.NameIdentified;
27.24 -
27.25 -/**
27.26 - *
27.27 - * @author Ing. František Kučera (frantovo.cz)
27.28 - */
27.29 -public class NamedParameter extends Parameter implements NameIdentified {
27.30 -
27.31 - private String name;
27.32 -
27.33 - public NamedParameter(String name, Object value, SQLType type) {
27.34 - super(value, type);
27.35 - this.name = name;
27.36 - }
27.37 -
27.38 - @Override
27.39 - public String getName() {
27.40 - return name;
27.41 - }
27.42 -
27.43 - public void setName(String name) {
27.44 - this.name = name;
27.45 - }
27.46 -
27.47 - @Override
27.48 - public String toString() {
27.49 - return "NamedParameter {" + name + " = " + getValue() + "; " + getType() + "}";
27.50 - }
27.51 -}
28.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/Parameter.java Mon Mar 04 17:06:42 2019 +0100
28.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
28.3 @@ -1,69 +0,0 @@
28.4 -/**
28.5 - * SQL-DK
28.6 - * Copyright © 2013 František Kučera (frantovo.cz)
28.7 - *
28.8 - * This program is free software: you can redistribute it and/or modify
28.9 - * it under the terms of the GNU General Public License as published by
28.10 - * the Free Software Foundation, either version 3 of the License, or
28.11 - * (at your option) any later version.
28.12 - *
28.13 - * This program is distributed in the hope that it will be useful,
28.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
28.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.16 - * GNU General Public License for more details.
28.17 - *
28.18 - * You should have received a copy of the GNU General Public License
28.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
28.20 - */
28.21 -package info.globalcode.sql.dk;
28.22 -
28.23 -import java.sql.Types;
28.24 -
28.25 -/**
28.26 - * Parameter for {@linkplain SQLCommand}
28.27 - *
28.28 - * @author Ing. František Kučera (frantovo.cz)
28.29 - */
28.30 -public class Parameter {
28.31 -
28.32 - /**
28.33 - * @see Types
28.34 - */
28.35 - public static final SQLType DEFAULT_TYPE = SQLType.VARCHAR;
28.36 - private Object value;
28.37 - private SQLType type;
28.38 -
28.39 - public Parameter() {
28.40 - }
28.41 -
28.42 - public Parameter(Object value, SQLType type) {
28.43 - this.value = value;
28.44 - if (type == null) {
28.45 - this.type = DEFAULT_TYPE;
28.46 - } else {
28.47 - this.type = type;
28.48 - }
28.49 - }
28.50 -
28.51 - public Object getValue() {
28.52 - return value;
28.53 - }
28.54 -
28.55 - public void setValue(Object value) {
28.56 - this.value = value;
28.57 - }
28.58 -
28.59 - /**
28.60 - * @see java.sql.Types
28.61 - */
28.62 - public SQLType getType() {
28.63 - return type;
28.64 - }
28.65 -
28.66 - /**
28.67 - * @see java.sql.Types
28.68 - */
28.69 - public void setType(SQLType type) {
28.70 - this.type = type;
28.71 - }
28.72 -}
29.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommand.java Mon Mar 04 17:06:42 2019 +0100
29.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
29.3 @@ -1,49 +0,0 @@
29.4 -/**
29.5 - * SQL-DK
29.6 - * Copyright © 2013 František Kučera (frantovo.cz)
29.7 - *
29.8 - * This program is free software: you can redistribute it and/or modify
29.9 - * it under the terms of the GNU General Public License as published by
29.10 - * the Free Software Foundation, either version 3 of the License, or
29.11 - * (at your option) any later version.
29.12 - *
29.13 - * This program is distributed in the hope that it will be useful,
29.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
29.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.16 - * GNU General Public License for more details.
29.17 - *
29.18 - * You should have received a copy of the GNU General Public License
29.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
29.20 - */
29.21 -package info.globalcode.sql.dk;
29.22 -
29.23 -import java.sql.Connection;
29.24 -import java.sql.PreparedStatement;
29.25 -import java.sql.SQLException;
29.26 -import java.util.List;
29.27 -
29.28 -/**
29.29 - * Represents SQL string and its parameters (if there are any).
29.30 - *
29.31 - * @author Ing. František Kučera (frantovo.cz)
29.32 - */
29.33 -public abstract class SQLCommand {
29.34 -
29.35 - private String query;
29.36 -
29.37 - public SQLCommand(String query) {
29.38 - this.query = query;
29.39 - }
29.40 -
29.41 - public PreparedStatement prepareStatement(Connection c) throws SQLException {
29.42 - return c.prepareStatement(query);
29.43 - }
29.44 -
29.45 - public abstract void parametrize(PreparedStatement ps) throws SQLException;
29.46 -
29.47 - public abstract List<? extends Parameter> getParameters();
29.48 -
29.49 - public String getQuery() {
29.50 - return query;
29.51 - }
29.52 -}
30.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNamed.java Mon Mar 04 17:06:42 2019 +0100
30.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
30.3 @@ -1,155 +0,0 @@
30.4 -/**
30.5 - * SQL-DK
30.6 - * Copyright © 2013 František Kučera (frantovo.cz)
30.7 - *
30.8 - * This program is free software: you can redistribute it and/or modify
30.9 - * it under the terms of the GNU General Public License as published by
30.10 - * the Free Software Foundation, either version 3 of the License, or
30.11 - * (at your option) any later version.
30.12 - *
30.13 - * This program is distributed in the hope that it will be useful,
30.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
30.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30.16 - * GNU General Public License for more details.
30.17 - *
30.18 - * You should have received a copy of the GNU General Public License
30.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
30.20 - */
30.21 -package info.globalcode.sql.dk;
30.22 -
30.23 -import static info.globalcode.sql.dk.Functions.findByName;
30.24 -import java.sql.Connection;
30.25 -import java.sql.PreparedStatement;
30.26 -import java.sql.SQLException;
30.27 -import java.util.ArrayList;
30.28 -import java.util.List;
30.29 -import java.util.logging.Level;
30.30 -import java.util.logging.Logger;
30.31 -import java.util.regex.Matcher;
30.32 -import java.util.regex.Pattern;
30.33 -import java.util.regex.PatternSyntaxException;
30.34 -
30.35 -/**
30.36 - * Has named parameters.
30.37 - *
30.38 - * @author Ing. František Kučera (frantovo.cz)
30.39 - */
30.40 -public class SQLCommandNamed extends SQLCommand {
30.41 -
30.42 - private static final Logger log = Logger.getLogger(SQLCommandNamed.class.getName());
30.43 - private String namePrefix;
30.44 - private String nameSuffix;
30.45 - private List<NamedParameter> parameters;
30.46 - private List<NamedParameter> parametersUsed = new ArrayList<>();
30.47 - private StringBuilder updatedQuery;
30.48 - private Pattern pattern;
30.49 - private SQLCommandNumbered numbered;
30.50 -
30.51 - public SQLCommandNamed(String query, List<NamedParameter> parameters, String namePrefix, String nameSuffix) {
30.52 - super(query);
30.53 - this.updatedQuery = new StringBuilder(query.length());
30.54 - this.parameters = parameters;
30.55 - this.namePrefix = namePrefix;
30.56 - this.nameSuffix = nameSuffix;
30.57 - }
30.58 -
30.59 - @Override
30.60 - public PreparedStatement prepareStatement(Connection c) throws SQLException {
30.61 - return getSQLCommandNumbered().prepareStatement(c);
30.62 - }
30.63 -
30.64 - @Override
30.65 - public void parametrize(PreparedStatement ps) throws SQLException {
30.66 - getSQLCommandNumbered().parametrize(ps);
30.67 - }
30.68 -
30.69 - private void prepare() throws SQLException {
30.70 - try {
30.71 - buildPattern();
30.72 - placeParametersAndUpdateQuery();
30.73 - logPossiblyMissingParameters();
30.74 - } catch (PatternSyntaxException e) {
30.75 - throw new SQLException("Name prefix „" + namePrefix + "“ or suffix „" + nameSuffix + "“ contain a wrong regular expression. " + e.getLocalizedMessage(), e);
30.76 - }
30.77 - }
30.78 -
30.79 - /**
30.80 - * @return SQL command with named parameters converted to SQL command with numbered parameters
30.81 - */
30.82 - public SQLCommandNumbered getSQLCommandNumbered() throws SQLException {
30.83 - if (numbered == null) {
30.84 - prepare();
30.85 - numbered = new SQLCommandNumbered(updatedQuery.toString(), parametersUsed);
30.86 - }
30.87 -
30.88 - return numbered;
30.89 - }
30.90 -
30.91 - /**
30.92 - * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has
30.93 - * one group: parameter name (without prefix/suffix)
30.94 - */
30.95 - private void buildPattern() throws PatternSyntaxException {
30.96 - StringBuilder patternString = new StringBuilder();
30.97 -
30.98 - patternString.append(namePrefix);
30.99 - patternString.append("(?<paramName>");
30.100 - for (int i = 0; i < parameters.size(); i++) {
30.101 - patternString.append(Pattern.quote(parameters.get(i).getName()));
30.102 - if (i < parameters.size() - 1) {
30.103 - patternString.append("|");
30.104 - }
30.105 - }
30.106 - patternString.append(")");
30.107 - patternString.append(nameSuffix);
30.108 -
30.109 - pattern = Pattern.compile(patternString.toString());
30.110 - }
30.111 -
30.112 - private void placeParametersAndUpdateQuery() {
30.113 - final String originalQuery = getQuery();
30.114 - Matcher m = pattern.matcher(originalQuery);
30.115 -
30.116 - int lastPosition = 0;
30.117 - while (m.find(lastPosition)) {
30.118 - String name = m.group("paramName");
30.119 -
30.120 - updatedQuery.append(originalQuery.substring(lastPosition, m.start()));
30.121 - updatedQuery.append("?");
30.122 -
30.123 - parametersUsed.add(findByName(parameters, name));
30.124 -
30.125 - lastPosition = m.end();
30.126 - }
30.127 - updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length()));
30.128 -
30.129 - for (NamedParameter definedParameter : parameters) {
30.130 - if (findByName(parametersUsed, definedParameter.getName()) == null) {
30.131 - /**
30.132 - * User can have predefined set of parameters and use them with different SQL
30.133 - * queries that use only subset of these parameters → just warning, not exception.
30.134 - */
30.135 - log.log(Level.WARNING, "Parameter „{0}“ is defined but not used in the query: „{1}“", new Object[]{definedParameter.getName(), originalQuery});
30.136 - }
30.137 - }
30.138 - }
30.139 -
30.140 - private void logPossiblyMissingParameters() {
30.141 - Pattern p = Pattern.compile(namePrefix + "(?<paramName>.+?)" + nameSuffix);
30.142 - Matcher m = p.matcher(updatedQuery);
30.143 - int lastPosition = 0;
30.144 - while (m.find(lastPosition)) {
30.145 - /**
30.146 - * We have not parsed and understood the SQL query; the parameter-like looking string
30.147 - * could be inside a literal part of the query → just warning, not exception.
30.148 - */
30.149 - log.log(Level.WARNING, "Possibly missing parameter „{0}“ in the query: „{1}“", new Object[]{m.group("paramName"), getQuery()});
30.150 - lastPosition = m.end();
30.151 - }
30.152 - }
30.153 -
30.154 - @Override
30.155 - public List<NamedParameter> getParameters() {
30.156 - return parameters;
30.157 - }
30.158 -}
31.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLCommandNumbered.java Mon Mar 04 17:06:42 2019 +0100
31.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
31.3 @@ -1,51 +0,0 @@
31.4 -/**
31.5 - * SQL-DK
31.6 - * Copyright © 2013 František Kučera (frantovo.cz)
31.7 - *
31.8 - * This program is free software: you can redistribute it and/or modify
31.9 - * it under the terms of the GNU General Public License as published by
31.10 - * the Free Software Foundation, either version 3 of the License, or
31.11 - * (at your option) any later version.
31.12 - *
31.13 - * This program is distributed in the hope that it will be useful,
31.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
31.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31.16 - * GNU General Public License for more details.
31.17 - *
31.18 - * You should have received a copy of the GNU General Public License
31.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
31.20 - */
31.21 -package info.globalcode.sql.dk;
31.22 -
31.23 -import static info.globalcode.sql.dk.Functions.notNull;
31.24 -import java.sql.PreparedStatement;
31.25 -import java.sql.SQLException;
31.26 -import java.util.List;
31.27 -
31.28 -/**
31.29 - * Has ordinal/numbered parameters.
31.30 - *
31.31 - * @author Ing. František Kučera (frantovo.cz)
31.32 - */
31.33 -public class SQLCommandNumbered extends SQLCommand {
31.34 -
31.35 - private List<? extends Parameter> parameters;
31.36 -
31.37 - public SQLCommandNumbered(String query, List<? extends Parameter> parameters) {
31.38 - super(query);
31.39 - this.parameters = parameters;
31.40 - }
31.41 -
31.42 - @Override
31.43 - public void parametrize(PreparedStatement ps) throws SQLException {
31.44 - int i = 1;
31.45 - for (Parameter p : notNull(parameters)) {
31.46 - ps.setObject(i++, p.getValue(), p.getType().getCode());
31.47 - }
31.48 - }
31.49 -
31.50 - @Override
31.51 - public List<? extends Parameter> getParameters() {
31.52 - return parameters;
31.53 - }
31.54 -}
32.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/SQLType.java Mon Mar 04 17:06:42 2019 +0100
32.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
32.3 @@ -1,95 +0,0 @@
32.4 -/**
32.5 - * SQL-DK
32.6 - * Copyright © 2013 František Kučera (frantovo.cz)
32.7 - *
32.8 - * This program is free software: you can redistribute it and/or modify
32.9 - * it under the terms of the GNU General Public License as published by
32.10 - * the Free Software Foundation, either version 3 of the License, or
32.11 - * (at your option) any later version.
32.12 - *
32.13 - * This program is distributed in the hope that it will be useful,
32.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
32.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.16 - * GNU General Public License for more details.
32.17 - *
32.18 - * You should have received a copy of the GNU General Public License
32.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
32.20 - */
32.21 -package info.globalcode.sql.dk;
32.22 -
32.23 -import java.sql.Types;
32.24 -
32.25 -/**
32.26 - * Data types of SQL parameters.
32.27 - *
32.28 - * @author Ing. František Kučera (frantovo.cz)
32.29 - */
32.30 -public enum SQLType {
32.31 -
32.32 - /**
32.33 - * Names must be upper case – user input is also converted to upper case → case insensitive
32.34 - */
32.35 - BIT(Types.BIT),
32.36 - TINYINT(Types.TINYINT),
32.37 - SMALLINT(Types.SMALLINT),
32.38 - INTEGER(Types.INTEGER),
32.39 - BIGINT(Types.BIGINT),
32.40 - FLOAT(Types.FLOAT),
32.41 - REAL(Types.REAL),
32.42 - DOUBLE(Types.DOUBLE),
32.43 - NUMERIC(Types.NUMERIC),
32.44 - DECIMAL(Types.DECIMAL),
32.45 - CHAR(Types.CHAR),
32.46 - VARCHAR(Types.VARCHAR),
32.47 - LONGVARCHAR(Types.LONGVARCHAR),
32.48 - DATE(Types.DATE),
32.49 - TIME(Types.TIME),
32.50 - TIMESTAMP(Types.TIMESTAMP),
32.51 - BINARY(Types.BINARY),
32.52 - VARBINARY(Types.VARBINARY),
32.53 - LONGVARBINARY(Types.LONGVARBINARY),
32.54 - NULL(Types.NULL),
32.55 - OTHER(Types.OTHER),
32.56 - JAVA_OBJECT(Types.JAVA_OBJECT),
32.57 - DISTINCT(Types.DISTINCT),
32.58 - STRUCT(Types.STRUCT),
32.59 - ARRAY(Types.ARRAY),
32.60 - BLOB(Types.BLOB),
32.61 - CLOB(Types.CLOB),
32.62 - REF(Types.REF),
32.63 - DATALINK(Types.DATALINK),
32.64 - BOOLEAN(Types.BOOLEAN),
32.65 - ROWID(Types.ROWID),
32.66 - NCHAR(Types.NCHAR),
32.67 - NVARCHAR(Types.NVARCHAR),
32.68 - LONGNVARCHAR(Types.LONGNVARCHAR),
32.69 - NCLOB(Types.NCLOB),
32.70 - SQLXML(Types.SQLXML);
32.71 - /** value from java.sql.Types */
32.72 - private int code;
32.73 -
32.74 - private SQLType(int code) {
32.75 - this.code = code;
32.76 - }
32.77 -
32.78 - /**
32.79 - * @see java.sql.Types.Types
32.80 - */
32.81 - public int getCode() {
32.82 - return code;
32.83 - }
32.84 -
32.85 - /**
32.86 - * @param code see {@linkplain java.sql.Types.Types}
32.87 - * @return found SQLType
32.88 - * @throws IllegalArgumentException if no data type has given code
32.89 - */
32.90 - public static SQLType valueOf(int code) {
32.91 - for (SQLType t : values()) {
32.92 - if (t.code == code) {
32.93 - return t;
32.94 - }
32.95 - }
32.96 - throw new IllegalArgumentException("No data type has code: " + code);
32.97 - }
32.98 -}
33.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/Xmlns.java Mon Mar 04 17:06:42 2019 +0100
33.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
33.3 @@ -1,33 +0,0 @@
33.4 -/**
33.5 - * SQL-DK
33.6 - * Copyright © 2013 František Kučera (frantovo.cz)
33.7 - *
33.8 - * This program is free software: you can redistribute it and/or modify
33.9 - * it under the terms of the GNU General Public License as published by
33.10 - * the Free Software Foundation, either version 3 of the License, or
33.11 - * (at your option) any later version.
33.12 - *
33.13 - * This program is distributed in the hope that it will be useful,
33.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
33.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33.16 - * GNU General Public License for more details.
33.17 - *
33.18 - * You should have received a copy of the GNU General Public License
33.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
33.20 - */
33.21 -package info.globalcode.sql.dk;
33.22 -
33.23 -/**
33.24 - * XML namespaces
33.25 - *
33.26 - * @author Ing. František Kučera (frantovo.cz)
33.27 - */
33.28 -public class Xmlns {
33.29 -
33.30 - public static final String CONFIGURATION = "https://sql-dk.globalcode.info/xmlns/configuration";
33.31 - public static final String BATCH_RESULT = "https://sql-dk.globalcode.info/xmlns/batchResult";
33.32 - public static final String XHTML = "http://www.w3.org/1999/xhtml";
33.33 -
33.34 - private Xmlns() {
33.35 - }
33.36 -}
34.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/batch/Batch.java Mon Mar 04 17:06:42 2019 +0100
34.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
34.3 @@ -1,32 +0,0 @@
34.4 -/**
34.5 - * SQL-DK
34.6 - * Copyright © 2013 František Kučera (frantovo.cz)
34.7 - *
34.8 - * This program is free software: you can redistribute it and/or modify
34.9 - * it under the terms of the GNU General Public License as published by
34.10 - * the Free Software Foundation, either version 3 of the License, or
34.11 - * (at your option) any later version.
34.12 - *
34.13 - * This program is distributed in the hope that it will be useful,
34.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
34.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34.16 - * GNU General Public License for more details.
34.17 - *
34.18 - * You should have received a copy of the GNU General Public License
34.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
34.20 - */
34.21 -package info.globalcode.sql.dk.batch;
34.22 -
34.23 -import info.globalcode.sql.dk.SQLCommand;
34.24 -
34.25 -/**
34.26 - * Iterator which reads SQL commands from encoded (serialized) batch.
34.27 - *
34.28 - * @author Ing. František Kučera (frantovo.cz)
34.29 - */
34.30 -public interface Batch {
34.31 -
34.32 - public boolean hasNext() throws BatchException;
34.33 -
34.34 - public SQLCommand next() throws BatchException;
34.35 -}
35.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/batch/BatchConstants.java Mon Mar 04 17:06:42 2019 +0100
35.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
35.3 @@ -1,35 +0,0 @@
35.4 -/**
35.5 - * SQL-DK
35.6 - * Copyright © 2014 František Kučera (frantovo.cz)
35.7 - *
35.8 - * This program is free software: you can redistribute it and/or modify
35.9 - * it under the terms of the GNU General Public License as published by
35.10 - * the Free Software Foundation, either version 3 of the License, or
35.11 - * (at your option) any later version.
35.12 - *
35.13 - * This program is distributed in the hope that it will be useful,
35.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
35.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35.16 - * GNU General Public License for more details.
35.17 - *
35.18 - * You should have received a copy of the GNU General Public License
35.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
35.20 - */
35.21 -package info.globalcode.sql.dk.batch;
35.22 -
35.23 -import java.nio.charset.Charset;
35.24 -import java.nio.charset.StandardCharsets;
35.25 -
35.26 -/**
35.27 - *
35.28 - * @author Ing. František Kučera (frantovo.cz)
35.29 - */
35.30 -public class BatchConstants {
35.31 -
35.32 - public static final Charset CHARSET = StandardCharsets.UTF_8;
35.33 - public static final byte VERSION = 0x01;
35.34 - public static final byte[] BATCH_HEADER = {0x00, 0x53, 0x51, 0x4C, VERSION};
35.35 -
35.36 - private BatchConstants() {
35.37 - }
35.38 -}
36.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/batch/BatchDecoder.java Mon Mar 04 17:06:42 2019 +0100
36.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
36.3 @@ -1,108 +0,0 @@
36.4 -/**
36.5 - * SQL-DK
36.6 - * Copyright © 2014 František Kučera (frantovo.cz)
36.7 - *
36.8 - * This program is free software: you can redistribute it and/or modify
36.9 - * it under the terms of the GNU General Public License as published by
36.10 - * the Free Software Foundation, either version 3 of the License, or
36.11 - * (at your option) any later version.
36.12 - *
36.13 - * This program is distributed in the hope that it will be useful,
36.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
36.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36.16 - * GNU General Public License for more details.
36.17 - *
36.18 - * You should have received a copy of the GNU General Public License
36.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
36.20 - */
36.21 -package info.globalcode.sql.dk.batch;
36.22 -
36.23 -import info.globalcode.sql.dk.Parameter;
36.24 -import info.globalcode.sql.dk.SQLCommand;
36.25 -import info.globalcode.sql.dk.SQLCommandNumbered;
36.26 -import java.io.DataInputStream;
36.27 -import java.io.InputStream;
36.28 -import static info.globalcode.sql.dk.batch.BatchConstants.*;
36.29 -import static info.globalcode.sql.dk.Functions.toHex;
36.30 -import info.globalcode.sql.dk.SQLType;
36.31 -import java.io.IOException;
36.32 -import java.util.ArrayList;
36.33 -import java.util.Arrays;
36.34 -import java.util.List;
36.35 -
36.36 -/**
36.37 - *
36.38 - * @author Ing. František Kučera (frantovo.cz)
36.39 - */
36.40 -public class BatchDecoder {
36.41 -
36.42 - public Batch decode(InputStream in) throws BatchException {
36.43 - return new BatchFromStream(new DataInputStream(in));
36.44 - }
36.45 -
36.46 - private class BatchFromStream implements Batch {
36.47 -
36.48 - private DataInputStream in;
36.49 - private boolean hasNext;
36.50 -
36.51 - public BatchFromStream(DataInputStream in) throws BatchException {
36.52 - this.in = in;
36.53 - hasNext = verifyHeader();
36.54 - }
36.55 -
36.56 - @Override
36.57 - public boolean hasNext() throws BatchException {
36.58 - return hasNext;
36.59 - }
36.60 -
36.61 - @Override
36.62 - public SQLCommand next() throws BatchException {
36.63 - try {
36.64 - String sql = readNextString();
36.65 -
36.66 - int paramCount = in.readInt();
36.67 - List<Parameter> parameters = new ArrayList<>(paramCount);
36.68 -
36.69 - for (int i = 0; i < paramCount; i++) {
36.70 - SQLType type = SQLType.valueOf(in.readInt());
36.71 - String value = readNextString();
36.72 - parameters.add(new Parameter(value, type));
36.73 - }
36.74 -
36.75 - hasNext = verifyHeader();
36.76 -
36.77 - SQLCommand sqlCommand = new SQLCommandNumbered(sql, parameters);
36.78 - return sqlCommand;
36.79 - } catch (IOException e) {
36.80 - throw new BatchException("Unable to read batch", e);
36.81 - }
36.82 - }
36.83 -
36.84 - private String readNextString() throws IOException {
36.85 - byte[] buffer = new byte[in.readInt()];
36.86 - in.read(buffer);
36.87 - return new String(buffer, CHARSET);
36.88 - }
36.89 -
36.90 - /**
36.91 - * @return true if correct batch header was found | false if EOF was found
36.92 - * @throws BatchException if unexpected data was found (not batch header nor EOF)
36.93 - */
36.94 - private boolean verifyHeader() throws BatchException {
36.95 - try {
36.96 - byte[] buffer = new byte[BATCH_HEADER.length];
36.97 - int bytesRead = in.read(buffer);
36.98 -
36.99 - if (bytesRead == BATCH_HEADER.length && Arrays.equals(buffer, BATCH_HEADER)) {
36.100 - return true;
36.101 - } else if (bytesRead == -1) {
36.102 - return false;
36.103 - } else {
36.104 - throw new BatchException("This is not SQL-DK batch: " + toHex(buffer));
36.105 - }
36.106 - } catch (IOException e) {
36.107 - throw new BatchException("Unable to read batch header", e);
36.108 - }
36.109 - }
36.110 - }
36.111 -}
37.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/batch/BatchEncoder.java Mon Mar 04 17:06:42 2019 +0100
37.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
37.3 @@ -1,83 +0,0 @@
37.4 -/**
37.5 - * SQL-DK
37.6 - * Copyright © 2014 František Kučera (frantovo.cz)
37.7 - *
37.8 - * This program is free software: you can redistribute it and/or modify
37.9 - * it under the terms of the GNU General Public License as published by
37.10 - * the Free Software Foundation, either version 3 of the License, or
37.11 - * (at your option) any later version.
37.12 - *
37.13 - * This program is distributed in the hope that it will be useful,
37.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
37.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37.16 - * GNU General Public License for more details.
37.17 - *
37.18 - * You should have received a copy of the GNU General Public License
37.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
37.20 - */
37.21 -package info.globalcode.sql.dk.batch;
37.22 -
37.23 -import info.globalcode.sql.dk.Parameter;
37.24 -import info.globalcode.sql.dk.SQLCommand;
37.25 -import info.globalcode.sql.dk.SQLCommandNamed;
37.26 -import java.io.DataOutputStream;
37.27 -import java.io.IOException;
37.28 -import java.io.OutputStream;
37.29 -import static info.globalcode.sql.dk.batch.BatchConstants.*;
37.30 -import java.io.ByteArrayOutputStream;
37.31 -import java.sql.SQLException;
37.32 -import java.util.List;
37.33 -
37.34 -/**
37.35 - *
37.36 - * @author Ing. František Kučera (frantovo.cz)
37.37 - */
37.38 -public class BatchEncoder {
37.39 -
37.40 - public int encode(SQLCommand sqlCommand, OutputStream out) throws BatchException {
37.41 - try {
37.42 - ByteArrayOutputStream bufferAOS = new ByteArrayOutputStream();
37.43 - DataOutputStream buffer = new DataOutputStream(bufferAOS);
37.44 -
37.45 - buffer.write(BATCH_HEADER);
37.46 -
37.47 - if (sqlCommand instanceof SQLCommandNamed) {
37.48 - sqlCommand = ((SQLCommandNamed) sqlCommand).getSQLCommandNumbered();
37.49 - }
37.50 -
37.51 - writeNextString(sqlCommand.getQuery(), buffer);
37.52 -
37.53 - List<? extends Parameter> parameters = sqlCommand.getParameters();
37.54 -
37.55 - buffer.writeInt(parameters.size());
37.56 -
37.57 - for (Parameter p : parameters) {
37.58 - buffer.writeInt(p.getType().getCode());
37.59 - writeNextString((String) p.getValue(), buffer); // parameters are encoded before any preprocessing
37.60 - }
37.61 -
37.62 - buffer.flush();
37.63 - bufferAOS.writeTo(out);
37.64 - out.flush();
37.65 - return bufferAOS.size();
37.66 - } catch (IOException e) {
37.67 - throw new BatchException("Unable to write SQL command: " + sqlCommand, e);
37.68 - } catch (SQLException e) {
37.69 - throw new BatchException("Unable to converd named SQL command to numbered: " + sqlCommand, e);
37.70 - }
37.71 - }
37.72 -
37.73 - private void writeNextString(String s, DataOutputStream out) throws IOException {
37.74 - byte[] bytes = toBytes(s);
37.75 - out.writeInt(bytes.length);
37.76 - out.write(bytes);
37.77 - }
37.78 -
37.79 - private static byte[] toBytes(String s) {
37.80 - if (s == null) {
37.81 - return new byte[]{};
37.82 - } else {
37.83 - return s.getBytes(CHARSET);
37.84 - }
37.85 - }
37.86 -}
38.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/batch/BatchException.java Mon Mar 04 17:06:42 2019 +0100
38.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
38.3 @@ -1,42 +0,0 @@
38.4 -/**
38.5 - * SQL-DK
38.6 - * Copyright © 2014 František Kučera (frantovo.cz)
38.7 - *
38.8 - * This program is free software: you can redistribute it and/or modify
38.9 - * it under the terms of the GNU General Public License as published by
38.10 - * the Free Software Foundation, either version 3 of the License, or
38.11 - * (at your option) any later version.
38.12 - *
38.13 - * This program is distributed in the hope that it will be useful,
38.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
38.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38.16 - * GNU General Public License for more details.
38.17 - *
38.18 - * You should have received a copy of the GNU General Public License
38.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
38.20 - */
38.21 -package info.globalcode.sql.dk.batch;
38.22 -
38.23 -import info.globalcode.sql.dk.DKException;
38.24 -
38.25 -/**
38.26 - *
38.27 - * @author Ing. František Kučera (frantovo.cz)
38.28 - */
38.29 -public class BatchException extends DKException {
38.30 -
38.31 - public BatchException() {
38.32 - }
38.33 -
38.34 - public BatchException(String message) {
38.35 - super(message);
38.36 - }
38.37 -
38.38 - public BatchException(Throwable cause) {
38.39 - super(cause);
38.40 - }
38.41 -
38.42 - public BatchException(String message, Throwable cause) {
38.43 - super(message, cause);
38.44 - }
38.45 -}
39.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/CommandArgument.java Mon Mar 04 17:06:42 2019 +0100
39.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
39.3 @@ -1,82 +0,0 @@
39.4 -/**
39.5 - * SQL-DK
39.6 - * Copyright © 2015 František Kučera (frantovo.cz)
39.7 - *
39.8 - * This program is free software: you can redistribute it and/or modify
39.9 - * it under the terms of the GNU General Public License as published by
39.10 - * the Free Software Foundation, either version 3 of the License, or
39.11 - * (at your option) any later version.
39.12 - *
39.13 - * This program is distributed in the hope that it will be useful,
39.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
39.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39.16 - * GNU General Public License for more details.
39.17 - *
39.18 - * You should have received a copy of the GNU General Public License
39.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
39.20 - */
39.21 -package info.globalcode.sql.dk.configuration;
39.22 -
39.23 -import javax.xml.bind.annotation.XmlAttribute;
39.24 -import javax.xml.bind.annotation.XmlEnum;
39.25 -import javax.xml.bind.annotation.XmlEnumValue;
39.26 -import javax.xml.bind.annotation.XmlValue;
39.27 -
39.28 -/**
39.29 - *
39.30 - * @author Ing. František Kučera (frantovo.cz)
39.31 - */
39.32 -public class CommandArgument {
39.33 -
39.34 - private String value;
39.35 - private TYPE type;
39.36 -
39.37 - @XmlEnum
39.38 - public static enum TYPE {
39.39 -
39.40 - /**
39.41 - * value = literal (text) argument
39.42 - */
39.43 - @XmlEnumValue("literal")
39.44 - LITERAL,
39.45 - /**
39.46 - * value will be substituted by hostname or IP address of the DB server
39.47 - */
39.48 - @XmlEnumValue("host")
39.49 - HOST,
39.50 - /**
39.51 - * value will be substituted by the port of the DB server
39.52 - */
39.53 - @XmlEnumValue("port")
39.54 - PORT,
39.55 - /**
39.56 - * value will be substituted by environmental variable of given name
39.57 - */
39.58 - @XmlEnumValue("env")
39.59 - ENVIRONMENT_VARIABLE,
39.60 - /**
39.61 - * value will be substituted by database property of given name
39.62 - */
39.63 - @XmlEnumValue("dbProperty")
39.64 - DB_PROPERTY;
39.65 - }
39.66 -
39.67 - @XmlValue
39.68 - public String getValue() {
39.69 - return value;
39.70 - }
39.71 -
39.72 - public void setValue(String value) {
39.73 - this.value = value;
39.74 - }
39.75 -
39.76 - @XmlAttribute(name = "type")
39.77 - public TYPE getType() {
39.78 - return type;
39.79 - }
39.80 -
39.81 - public void setType(TYPE type) {
39.82 - this.type = type;
39.83 - }
39.84 -
39.85 -}
40.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Configuration.java Mon Mar 04 17:06:42 2019 +0100
40.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
40.3 @@ -1,173 +0,0 @@
40.4 -/**
40.5 - * SQL-DK
40.6 - * Copyright © 2013 František Kučera (frantovo.cz)
40.7 - *
40.8 - * This program is free software: you can redistribute it and/or modify
40.9 - * it under the terms of the GNU General Public License as published by
40.10 - * the Free Software Foundation, either version 3 of the License, or
40.11 - * (at your option) any later version.
40.12 - *
40.13 - * This program is distributed in the hope that it will be useful,
40.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
40.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40.16 - * GNU General Public License for more details.
40.17 - *
40.18 - * You should have received a copy of the GNU General Public License
40.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
40.20 - */
40.21 -package info.globalcode.sql.dk.configuration;
40.22 -
40.23 -import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
40.24 -import static info.globalcode.sql.dk.Functions.findByName;
40.25 -import info.globalcode.sql.dk.formatting.BarChartFormatter;
40.26 -import info.globalcode.sql.dk.formatting.SilentFormatter;
40.27 -import info.globalcode.sql.dk.formatting.SingleRecordFormatter;
40.28 -import info.globalcode.sql.dk.formatting.SingleValueFormatter;
40.29 -import info.globalcode.sql.dk.formatting.TabularFormatter;
40.30 -import info.globalcode.sql.dk.formatting.TabularPrefetchingFormatter;
40.31 -import info.globalcode.sql.dk.formatting.TabularWrappingFormatter;
40.32 -import info.globalcode.sql.dk.formatting.TeXFormatter;
40.33 -import info.globalcode.sql.dk.formatting.XhtmlFormatter;
40.34 -import info.globalcode.sql.dk.formatting.XmlFormatter;
40.35 -import java.util.ArrayList;
40.36 -import java.util.Collection;
40.37 -import java.util.Collections;
40.38 -import java.util.List;
40.39 -import javax.xml.bind.annotation.XmlElement;
40.40 -import javax.xml.bind.annotation.XmlRootElement;
40.41 -import javax.xml.bind.annotation.XmlTransient;
40.42 -
40.43 -/**
40.44 - * Object representation of user configuration loaded from XML.
40.45 - *
40.46 - * @author Ing. František Kučera (frantovo.cz)
40.47 - */
40.48 -@XmlRootElement(name = "configuration", namespace = CONFIGURATION)
40.49 -public class Configuration {
40.50 -
40.51 - private List<DatabaseDefinition> databases = new ArrayList<>();
40.52 - private List<FormatterDefinition> formatters = new ArrayList<>();
40.53 - /**
40.54 - * is used if no formatter is specified on CLI nor in user configuration
40.55 - */
40.56 - public static final String DEFAULT_FORMATTER = TabularFormatter.NAME;
40.57 - /**
40.58 - * Can be used as default if prefetching is ok – for configuration listings (config is alread in
40.59 - * memory, so this does not matter)
40.60 - */
40.61 - public static final String DEFAULT_FORMATTER_PREFETCHING = TabularPrefetchingFormatter.NAME;
40.62 - private String defaultFormatter;
40.63 - /**
40.64 - * Default list of formatters. Is used if particular name is not found in user configuration.
40.65 - */
40.66 - private static final Collection<FormatterDefinition> buildInFormatters;
40.67 -
40.68 - static {
40.69 - Collection<FormatterDefinition> l = new ArrayList<>();
40.70 - l.add(new FormatterDefinition(SilentFormatter.NAME, SilentFormatter.class.getName()));
40.71 - l.add(new FormatterDefinition(SingleValueFormatter.NAME, SingleValueFormatter.class.getName()));
40.72 - l.add(new FormatterDefinition(SingleRecordFormatter.NAME, SingleRecordFormatter.class.getName()));
40.73 - l.add(new FormatterDefinition(XmlFormatter.NAME, XmlFormatter.class.getName()));
40.74 - l.add(new FormatterDefinition(XhtmlFormatter.NAME, XhtmlFormatter.class.getName()));
40.75 - l.add(new FormatterDefinition(TabularFormatter.NAME, TabularFormatter.class.getName()));
40.76 - l.add(new FormatterDefinition(TabularPrefetchingFormatter.NAME, TabularPrefetchingFormatter.class.getName()));
40.77 - l.add(new FormatterDefinition(TabularWrappingFormatter.NAME, TabularWrappingFormatter.class.getName()));
40.78 - l.add(new FormatterDefinition(TeXFormatter.NAME, TeXFormatter.class.getName()));
40.79 - //l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
40.80 - //l.add(new FormatterDefinition(SystemCommandExecutor.NAME, SystemCommandExecutor.class.getName()));
40.81 - l.add(new FormatterDefinition(BarChartFormatter.NAME, BarChartFormatter.class.getName()));
40.82 - buildInFormatters = Collections.unmodifiableCollection(l);
40.83 - }
40.84 -
40.85 - @XmlElement(name = "database", namespace = CONFIGURATION)
40.86 - public List<DatabaseDefinition> getDatabases() {
40.87 - return databases;
40.88 - }
40.89 -
40.90 - public void setDatabases(List<DatabaseDefinition> databases) {
40.91 - this.databases = databases;
40.92 - }
40.93 -
40.94 - /**
40.95 - * @param name
40.96 - * @return
40.97 - * @throws ConfigurationException if no database with this name is configured
40.98 - */
40.99 - public DatabaseDefinition getDatabase(String name) throws ConfigurationException {
40.100 - DatabaseDefinition dd = findByName(databases, name);
40.101 - if (dd == null) {
40.102 - throw new ConfigurationException("Database is not configured: " + name);
40.103 - } else {
40.104 - return dd;
40.105 - }
40.106 - }
40.107 -
40.108 - /**
40.109 - * @return only configured formatters
40.110 - * @see #getBuildInFormatters()
40.111 - * @see #getAllFormatters()
40.112 - */
40.113 - @XmlElement(name = "formatter", namespace = CONFIGURATION)
40.114 - public List<FormatterDefinition> getFormatters() {
40.115 - return formatters;
40.116 - }
40.117 -
40.118 - public void setFormatters(List<FormatterDefinition> formatters) {
40.119 - this.formatters = formatters;
40.120 - }
40.121 -
40.122 - /**
40.123 - * @param name name of desired formatter. Looking for this name in user configuration, then in
40.124 - * buil-in formatters. If null, default from configuration or (if not configured) built-in
40.125 - * default is used.
40.126 - * @return formatter definition
40.127 - * @throws ConfigurationException if no formatter with this name was found
40.128 - */
40.129 - public FormatterDefinition getFormatter(String name) throws ConfigurationException {
40.130 - if (name == null) {
40.131 - return defaultFormatter == null ? getFormatter(DEFAULT_FORMATTER) : getFormatter(defaultFormatter);
40.132 - } else {
40.133 - FormatterDefinition fd = findByName(formatters, name);
40.134 - fd = fd == null ? findByName(buildInFormatters, name) : fd;
40.135 - if (fd == null) {
40.136 - throw new ConfigurationException("Formatter is not configured: " + name);
40.137 - } else {
40.138 - return fd;
40.139 - }
40.140 - }
40.141 - }
40.142 -
40.143 - /**
40.144 - * @return only built-in formatters
40.145 - * @see #getAllFormatters()
40.146 - * @see #getFormatters()
40.147 - */
40.148 - @XmlTransient
40.149 - public Collection<FormatterDefinition> getBuildInFormatters() {
40.150 - return buildInFormatters;
40.151 - }
40.152 -
40.153 - /**
40.154 - * @return built-in + configured formatters
40.155 - * @see #getFormatters()
40.156 - */
40.157 - @XmlTransient
40.158 - public Collection<FormatterDefinition> getAllFormatters() {
40.159 - Collection<FormatterDefinition> allFormatters = new ArrayList<>();
40.160 - allFormatters.addAll(buildInFormatters);
40.161 - allFormatters.addAll(formatters);
40.162 - return allFormatters;
40.163 - }
40.164 -
40.165 - /**
40.166 - * @return name of default formatter, is used if name is not specified on CLI
40.167 - */
40.168 - @XmlElement(name = "defaultFormatter", namespace = CONFIGURATION)
40.169 - public String getDefaultFormatter() {
40.170 - return defaultFormatter;
40.171 - }
40.172 -
40.173 - public void setDefaultFormatter(String defaultFormatter) {
40.174 - this.defaultFormatter = defaultFormatter;
40.175 - }
40.176 -}
41.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/ConfigurationException.java Mon Mar 04 17:06:42 2019 +0100
41.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
41.3 @@ -1,42 +0,0 @@
41.4 -/**
41.5 - * SQL-DK
41.6 - * Copyright © 2013 František Kučera (frantovo.cz)
41.7 - *
41.8 - * This program is free software: you can redistribute it and/or modify
41.9 - * it under the terms of the GNU General Public License as published by
41.10 - * the Free Software Foundation, either version 3 of the License, or
41.11 - * (at your option) any later version.
41.12 - *
41.13 - * This program is distributed in the hope that it will be useful,
41.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
41.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41.16 - * GNU General Public License for more details.
41.17 - *
41.18 - * You should have received a copy of the GNU General Public License
41.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
41.20 - */
41.21 -package info.globalcode.sql.dk.configuration;
41.22 -
41.23 -import info.globalcode.sql.dk.DKException;
41.24 -
41.25 -/**
41.26 - *
41.27 - * @author Ing. František Kučera (frantovo.cz)
41.28 - */
41.29 -public class ConfigurationException extends DKException {
41.30 -
41.31 - public ConfigurationException() {
41.32 - }
41.33 -
41.34 - public ConfigurationException(String message) {
41.35 - super(message);
41.36 - }
41.37 -
41.38 - public ConfigurationException(Throwable cause) {
41.39 - super(cause);
41.40 - }
41.41 -
41.42 - public ConfigurationException(String message, Throwable cause) {
41.43 - super(message, cause);
41.44 - }
41.45 -}
42.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/ConfigurationProvider.java Mon Mar 04 17:06:42 2019 +0100
42.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
42.3 @@ -1,28 +0,0 @@
42.4 -/**
42.5 - * SQL-DK
42.6 - * Copyright © 2013 František Kučera (frantovo.cz)
42.7 - *
42.8 - * This program is free software: you can redistribute it and/or modify
42.9 - * it under the terms of the GNU General Public License as published by
42.10 - * the Free Software Foundation, either version 3 of the License, or
42.11 - * (at your option) any later version.
42.12 - *
42.13 - * This program is distributed in the hope that it will be useful,
42.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
42.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42.16 - * GNU General Public License for more details.
42.17 - *
42.18 - * You should have received a copy of the GNU General Public License
42.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
42.20 - */
42.21 -package info.globalcode.sql.dk.configuration;
42.22 -
42.23 -/**
42.24 - * Use for lazy-loading of the configuration.
42.25 - *
42.26 - * @author Ing. František Kučera (frantovo.cz)
42.27 - */
42.28 -public interface ConfigurationProvider {
42.29 -
42.30 - public Configuration getConfiguration() throws ConfigurationException;
42.31 -}
43.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/DatabaseDefinition.java Mon Mar 04 17:06:42 2019 +0100
43.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
43.3 @@ -1,147 +0,0 @@
43.4 -/**
43.5 - * SQL-DK
43.6 - * Copyright © 2013 František Kučera (frantovo.cz)
43.7 - *
43.8 - * This program is free software: you can redistribute it and/or modify
43.9 - * it under the terms of the GNU General Public License as published by
43.10 - * the Free Software Foundation, either version 3 of the License, or
43.11 - * (at your option) any later version.
43.12 - *
43.13 - * This program is distributed in the hope that it will be useful,
43.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
43.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43.16 - * GNU General Public License for more details.
43.17 - *
43.18 - * You should have received a copy of the GNU General Public License
43.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
43.20 - */
43.21 -package info.globalcode.sql.dk.configuration;
43.22 -
43.23 -import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
43.24 -import info.globalcode.sql.dk.DatabaseConnection;
43.25 -import info.globalcode.sql.dk.jmx.ConnectionManagement;
43.26 -import java.sql.SQLException;
43.27 -import java.util.logging.Logger;
43.28 -import javax.xml.bind.annotation.XmlElement;
43.29 -
43.30 -/**
43.31 - * Configured (but not yet connected) database connection.
43.32 - *
43.33 - * @author Ing. František Kučera (frantovo.cz)
43.34 - */
43.35 -public class DatabaseDefinition implements NameIdentified {
43.36 -
43.37 - private static final Logger log = Logger.getLogger(DatabaseDefinition.class.getName());
43.38 - /**
43.39 - * database name in SQL-DK configuration
43.40 - */
43.41 - private String name;
43.42 - /**
43.43 - * JDBC URL
43.44 - */
43.45 - private String url;
43.46 - /**
43.47 - * JDBC user name
43.48 - */
43.49 - private String userName;
43.50 - /**
43.51 - * JDBC password
43.52 - */
43.53 - private String password;
43.54 - /**
43.55 - * optional JDBC driver – if empty, the DriverManager is used to lookup specific Driver for
43.56 - * given URL
43.57 - */
43.58 - private String driver;
43.59 - /**
43.60 - * JDBC properties
43.61 - */
43.62 - private Properties properties = new Properties();
43.63 - /**
43.64 - * optional definition of tunnel to the remote database
43.65 - */
43.66 - private TunnelDefinition tunnel;
43.67 -
43.68 - @XmlElement(name = "name", namespace = CONFIGURATION)
43.69 - @Override
43.70 - public String getName() {
43.71 - return name;
43.72 - }
43.73 -
43.74 - public void setName(String name) {
43.75 - this.name = name;
43.76 - }
43.77 -
43.78 - @XmlElement(name = "url", namespace = CONFIGURATION)
43.79 - public String getUrl() {
43.80 - return url;
43.81 - }
43.82 -
43.83 - public void setUrl(String url) {
43.84 - this.url = url;
43.85 - }
43.86 -
43.87 - @XmlElement(name = "userName", namespace = CONFIGURATION)
43.88 - public String getUserName() {
43.89 - return userName;
43.90 - }
43.91 -
43.92 - public void setUserName(String userName) {
43.93 - this.userName = userName;
43.94 - }
43.95 -
43.96 - @XmlElement(name = "password", namespace = CONFIGURATION)
43.97 - public String getPassword() {
43.98 - return password;
43.99 - }
43.100 -
43.101 - public void setPassword(String password) {
43.102 - this.password = password;
43.103 - }
43.104 -
43.105 - public String getDriver() {
43.106 - return driver;
43.107 - }
43.108 -
43.109 - public void setDriver(String driver) {
43.110 - this.driver = driver;
43.111 - }
43.112 -
43.113 - @XmlElement(name = "property", namespace = CONFIGURATION)
43.114 - public Properties getProperties() {
43.115 - return properties;
43.116 - }
43.117 -
43.118 - public void setProperties(Properties properties) {
43.119 - this.properties = properties;
43.120 - }
43.121 -
43.122 - public TunnelDefinition getTunnel() {
43.123 - return tunnel;
43.124 - }
43.125 -
43.126 - public void setTunnel(TunnelDefinition tunnel) {
43.127 - this.tunnel = tunnel;
43.128 - }
43.129 -
43.130 - /**
43.131 - * @param properties ad-hoc properties from CLI options (for the JDBC driver)
43.132 - * @param jmxBean JMX management bean for progress reporting | null = disable JMX
43.133 - * @return
43.134 - * @throws java.sql.SQLException
43.135 - */
43.136 - public DatabaseConnection connect(Properties properties, ConnectionManagement jmxBean) throws SQLException {
43.137 - return new DatabaseConnection(this, properties, jmxBean);
43.138 - }
43.139 -
43.140 - /**
43.141 - * @param properties
43.142 - * @return
43.143 - * @throws java.sql.SQLException
43.144 - * @see #connect(info.globalcode.sql.dk.configuration.Properties, java.lang.String)
43.145 - * With disabled JMX reporting.
43.146 - */
43.147 - public DatabaseConnection connect(Properties properties) throws SQLException {
43.148 - return new DatabaseConnection(this, properties, null);
43.149 - }
43.150 -}
44.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/FormatterDefinition.java Mon Mar 04 17:06:42 2019 +0100
44.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
44.3 @@ -1,114 +0,0 @@
44.4 -/**
44.5 - * SQL-DK
44.6 - * Copyright © 2013 František Kučera (frantovo.cz)
44.7 - *
44.8 - * This program is free software: you can redistribute it and/or modify
44.9 - * it under the terms of the GNU General Public License as published by
44.10 - * the Free Software Foundation, either version 3 of the License, or
44.11 - * (at your option) any later version.
44.12 - *
44.13 - * This program is distributed in the hope that it will be useful,
44.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
44.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44.16 - * GNU General Public License for more details.
44.17 - *
44.18 - * You should have received a copy of the GNU General Public License
44.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
44.20 - */
44.21 -package info.globalcode.sql.dk.configuration;
44.22 -
44.23 -import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
44.24 -import info.globalcode.sql.dk.formatting.Formatter;
44.25 -import info.globalcode.sql.dk.formatting.FormatterContext;
44.26 -import info.globalcode.sql.dk.formatting.FormatterException;
44.27 -import java.lang.reflect.Constructor;
44.28 -import java.lang.reflect.InvocationTargetException;
44.29 -import javax.xml.bind.annotation.XmlElement;
44.30 -
44.31 -/**
44.32 - * Configured (but not yet instantiated) formatter.
44.33 - *
44.34 - * @author Ing. František Kučera (frantovo.cz)
44.35 - */
44.36 -public class FormatterDefinition implements NameIdentified {
44.37 -
44.38 - private String name;
44.39 - private String className;
44.40 - private Properties properties = new Properties();
44.41 -
44.42 - public FormatterDefinition() {
44.43 - }
44.44 -
44.45 - public FormatterDefinition(String name, String className) {
44.46 - this.name = name;
44.47 - this.className = className;
44.48 - }
44.49 -
44.50 - public FormatterDefinition(String name, String className, Properties properties) {
44.51 - this(name, className);
44.52 - this.properties = properties;
44.53 - }
44.54 -
44.55 - @XmlElement(name = "name", namespace = CONFIGURATION)
44.56 - @Override
44.57 - public String getName() {
44.58 - return name;
44.59 - }
44.60 -
44.61 - public void setName(String name) {
44.62 - this.name = name;
44.63 - }
44.64 -
44.65 - /**
44.66 - * Filter's class. Must implement the
44.67 - * <code>info.globalcode.sql.dk.formatting.Formatter</code> interface.
44.68 - * Subclassing the
44.69 - * <code>info.globalcode.sql.dk.formatting.AbstractFormatter</code> is strongly recommended.
44.70 - * The constructor must accept one parameter:
44.71 - * <code>info.globalcode.sql.dk.formatting.FormatterContext</code>
44.72 - *
44.73 - * @return fully qualified class name
44.74 - */
44.75 - @XmlElement(name = "class", namespace = CONFIGURATION)
44.76 - public String getClassName() {
44.77 - return className;
44.78 - }
44.79 -
44.80 - public void setClassName(String className) {
44.81 - this.className = className;
44.82 - }
44.83 -
44.84 - @XmlElement(name = "property", namespace = CONFIGURATION)
44.85 - public Properties getProperties() {
44.86 - return properties;
44.87 - }
44.88 -
44.89 - public void setProperties(Properties properties) {
44.90 - this.properties = properties;
44.91 - }
44.92 -
44.93 - /**
44.94 - * @param context
44.95 - * @return
44.96 - * @throws FormatterException
44.97 - */
44.98 - public Formatter getInstance(FormatterContext context) throws FormatterException {
44.99 - context.getProperties().setDefaults(properties);
44.100 - try {
44.101 - Constructor constructor = Class.forName(className).getConstructor(context.getClass());
44.102 -
44.103 - Object instance = constructor.newInstance(context);
44.104 - if (instance instanceof Formatter) {
44.105 - return (Formatter) instance;
44.106 - } else {
44.107 - throw new FormatterException("Formatter " + instance + " does not implement the " + Formatter.class.getName() + " interface");
44.108 - }
44.109 - } catch (ClassNotFoundException e) {
44.110 - throw new FormatterException("Formatter class does not exist: " + className, e);
44.111 - } catch (NoSuchMethodException e) {
44.112 - throw new FormatterException("Formatter class with no valid constructor: " + className, e);
44.113 - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
44.114 - throw new FormatterException("Formatter's constructor caused an error: " + className, e);
44.115 - }
44.116 - }
44.117 -}
45.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Loader.java Mon Mar 04 17:06:42 2019 +0100
45.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
45.3 @@ -1,101 +0,0 @@
45.4 -/**
45.5 - * SQL-DK
45.6 - * Copyright © 2015 František Kučera (frantovo.cz)
45.7 - *
45.8 - * This program is free software: you can redistribute it and/or modify
45.9 - * it under the terms of the GNU General Public License as published by
45.10 - * the Free Software Foundation, either version 3 of the License, or
45.11 - * (at your option) any later version.
45.12 - *
45.13 - * This program is distributed in the hope that it will be useful,
45.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
45.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45.16 - * GNU General Public License for more details.
45.17 - *
45.18 - * You should have received a copy of the GNU General Public License
45.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
45.20 - */
45.21 -package info.globalcode.sql.dk.configuration;
45.22 -
45.23 -import info.globalcode.sql.dk.*;
45.24 -import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_USER;
45.25 -import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_PASSWORD;
45.26 -import java.sql.Connection;
45.27 -import java.sql.Driver;
45.28 -import java.sql.DriverManager;
45.29 -import java.sql.SQLException;
45.30 -import java.util.logging.Level;
45.31 -import java.util.logging.Logger;
45.32 -import javax.xml.bind.JAXBContext;
45.33 -import javax.xml.bind.Unmarshaller;
45.34 -
45.35 -/**
45.36 - * Configuration loader – deserializes Configuration from the XML file.
45.37 - *
45.38 - * @author Ing. František Kučera (frantovo.cz)
45.39 - */
45.40 -public class Loader {
45.41 -
45.42 - private static final Logger log = Logger.getLogger(Loader.class.getName());
45.43 -
45.44 - public Configuration loadConfiguration() throws ConfigurationException {
45.45 - try {
45.46 - JAXBContext jaxb = JAXBContext.newInstance(Configuration.class.getPackage().getName(), Configuration.class.getClassLoader());
45.47 - Unmarshaller u = jaxb.createUnmarshaller();
45.48 - return (Configuration) u.unmarshal(Constants.CONFIG_FILE);
45.49 - } catch (Exception e) {
45.50 - throw new ConfigurationException("Unable to load configuration from " + Constants.CONFIG_FILE, e);
45.51 - }
45.52 - }
45.53 -
45.54 - /**
45.55 - * JDBC connection should not be used directly in SQL-DK.
45.56 - *
45.57 - * @see DatabaseDefinition#connect(info.globalcode.sql.dk.configuration.Properties)
45.58 - * @param properties
45.59 - * @param databaseDefinition
45.60 - * @return
45.61 - * @throws java.sql.SQLException
45.62 - */
45.63 - public static Connection jdbcConnect(DatabaseDefinition databaseDefinition, Properties properties) throws SQLException {
45.64 - synchronized (properties) {
45.65 - /**
45.66 - * Avoid rewriting the properties. Usually, the connection is created only once, but
45.67 - * with --test-connection and with SQL-DK JDBC driver, it might be reused.
45.68 - */
45.69 - properties = properties.clone();
45.70 - }
45.71 - if (properties.hasProperty(JDBC_PROPERTY_PASSWORD)) {
45.72 - log.log(Level.WARNING, "Passing DB password as CLI parameter is insecure!");
45.73 - }
45.74 - Properties credentials = new Properties();
45.75 - credentials.add(new Property(JDBC_PROPERTY_USER, databaseDefinition.getUserName()));
45.76 - credentials.add(new Property(JDBC_PROPERTY_PASSWORD, databaseDefinition.getPassword()));
45.77 - credentials.setDefaults(databaseDefinition.getProperties());
45.78 - properties.setDefaults(credentials);
45.79 - java.util.Properties javaProperties = properties.getJavaProperties();
45.80 -
45.81 - String driverClassName = databaseDefinition.getDriver();
45.82 - final String url = databaseDefinition.getUrl();
45.83 - if (driverClassName == null) {
45.84 - log.log(Level.FINE, "Using DriverManager to create connection for „{0}“", url);
45.85 - return DriverManager.getConnection(url, javaProperties);
45.86 - } else {
45.87 - log.log(Level.FINE, "Using custom Driver „{0}“ to create connection for „{1}“", new Object[]{driverClassName, url});
45.88 - try {
45.89 - Class<Driver> driverClass = (Class<Driver>) Class.forName(driverClassName);
45.90 - Driver driver = driverClass.newInstance();
45.91 - Connection connection = driver.connect(url, javaProperties);
45.92 - if (connection == null) {
45.93 - log.log(Level.SEVERE, "Driver „{0}“ returend null → it does not accept the URL: „{1}“", new Object[]{driverClassName, url});
45.94 - throw new SQLException("Unable to connect: driver returned null.");
45.95 - } else {
45.96 - return connection;
45.97 - }
45.98 - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException e) {
45.99 - throw new SQLException("Unable to connect usig specific driver: " + driverClassName, e);
45.100 - }
45.101 - }
45.102 - }
45.103 -
45.104 -}
46.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/NameIdentified.java Mon Mar 04 17:06:42 2019 +0100
46.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
46.3 @@ -1,27 +0,0 @@
46.4 -/**
46.5 - * SQL-DK
46.6 - * Copyright © 2013 František Kučera (frantovo.cz)
46.7 - *
46.8 - * This program is free software: you can redistribute it and/or modify
46.9 - * it under the terms of the GNU General Public License as published by
46.10 - * the Free Software Foundation, either version 3 of the License, or
46.11 - * (at your option) any later version.
46.12 - *
46.13 - * This program is distributed in the hope that it will be useful,
46.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
46.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46.16 - * GNU General Public License for more details.
46.17 - *
46.18 - * You should have received a copy of the GNU General Public License
46.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
46.20 - */
46.21 -package info.globalcode.sql.dk.configuration;
46.22 -
46.23 -/**
46.24 - *
46.25 - * @author Ing. František Kučera (frantovo.cz)
46.26 - */
46.27 -public interface NameIdentified {
46.28 -
46.29 - public String getName();
46.30 -}
47.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Properties.java Mon Mar 04 17:06:42 2019 +0100
47.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
47.3 @@ -1,129 +0,0 @@
47.4 -/**
47.5 - * SQL-DK
47.6 - * Copyright © 2013 František Kučera (frantovo.cz)
47.7 - *
47.8 - * This program is free software: you can redistribute it and/or modify
47.9 - * it under the terms of the GNU General Public License as published by
47.10 - * the Free Software Foundation, either version 3 of the License, or
47.11 - * (at your option) any later version.
47.12 - *
47.13 - * This program is distributed in the hope that it will be useful,
47.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
47.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.16 - * GNU General Public License for more details.
47.17 - *
47.18 - * You should have received a copy of the GNU General Public License
47.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
47.20 - */
47.21 -package info.globalcode.sql.dk.configuration;
47.22 -
47.23 -import java.util.ArrayList;
47.24 -import javax.xml.bind.annotation.XmlTransient;
47.25 -import static info.globalcode.sql.dk.Functions.findByName;
47.26 -import java.util.Collections;
47.27 -
47.28 -/**
47.29 - * <p>
47.30 - * List of configurables.</p>
47.31 - *
47.32 - * <p>
47.33 - * Can be backed by defaults – if value for given name is nof found in this instance, we will
47.34 - * look into defaults. Methods also accept defaultValue parameter – is used if property is nof found
47.35 - * even in default properties.</p>
47.36 - *
47.37 - * <p>
47.38 - * Typical use: </p>
47.39 - * <ul>
47.40 - * <li>this instance – ad-hoc properties from CLI options</li>
47.41 - * <li>default properties – from config file</li>
47.42 - * <li>defaultValue – hardcoded default</li>
47.43 - * </ul>
47.44 - *
47.45 - * @author Ing. František Kučera (frantovo.cz)
47.46 - */
47.47 -public class Properties extends ArrayList<Property> implements Cloneable {
47.48 -
47.49 - private Properties defaults;
47.50 -
47.51 - public Properties() {
47.52 - }
47.53 -
47.54 - public Properties(int initialCapacity) {
47.55 - super(initialCapacity);
47.56 - }
47.57 -
47.58 - @XmlTransient
47.59 - public Properties getDefaults() {
47.60 - return defaults;
47.61 - }
47.62 -
47.63 - public void setDefaults(Properties defaults) {
47.64 - this.defaults = defaults;
47.65 - }
47.66 -
47.67 - /**
47.68 - * @param defaults the last/deepest defaults
47.69 - */
47.70 - public void setLastDefaults(Properties defaults) {
47.71 - if (this.defaults == null) {
47.72 - this.defaults = defaults;
47.73 - } else {
47.74 - this.defaults.setLastDefaults(defaults);
47.75 - }
47.76 - }
47.77 -
47.78 - private Property findProperty(String name) {
47.79 - Property p = findByName(this, name);
47.80 - if (p == null && defaults != null) {
47.81 - p = defaults.findProperty(name);
47.82 - }
47.83 - return p;
47.84 - }
47.85 -
47.86 - public String getString(String name, String defaultValue) {
47.87 - Property p = findProperty(name);
47.88 - return p == null ? defaultValue : p.getValue();
47.89 - }
47.90 -
47.91 - public boolean getBoolean(String name, boolean defaultValue) {
47.92 - Property p = findProperty(name);
47.93 - return p == null ? defaultValue : Boolean.valueOf(p.getValue());
47.94 - }
47.95 -
47.96 - public int getInteger(String name, int defaultValue) {
47.97 - Property p = findProperty(name);
47.98 - return p == null ? defaultValue : Integer.valueOf(p.getValue());
47.99 - }
47.100 -
47.101 - public boolean hasProperty(String name) {
47.102 - return findByName(this, name) != null;
47.103 - }
47.104 -
47.105 - @Override
47.106 - public Properties clone() {
47.107 - Properties clone = new Properties(size());
47.108 - Collections.copy(clone, this);
47.109 - return clone;
47.110 - }
47.111 -
47.112 - /**
47.113 - * @return merged this and backing defaults as Java Properties
47.114 - */
47.115 - public java.util.Properties getJavaProperties() {
47.116 - java.util.Properties javaProperties = new java.util.Properties();
47.117 - duplicateTo(javaProperties);
47.118 - return javaProperties;
47.119 - }
47.120 -
47.121 - private void duplicateTo(java.util.Properties javaProperties) {
47.122 - if (defaults != null) {
47.123 - defaults.duplicateTo(javaProperties);
47.124 - }
47.125 - for (Property p : this) {
47.126 - String value = p.getValue();
47.127 - if (value != null) {
47.128 - javaProperties.setProperty(p.getName(), value);
47.129 - }
47.130 - }
47.131 - }
47.132 -}
48.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/Property.java Mon Mar 04 17:06:42 2019 +0100
48.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
48.3 @@ -1,69 +0,0 @@
48.4 -/**
48.5 - * SQL-DK
48.6 - * Copyright © 2013 František Kučera (frantovo.cz)
48.7 - *
48.8 - * This program is free software: you can redistribute it and/or modify
48.9 - * it under the terms of the GNU General Public License as published by
48.10 - * the Free Software Foundation, either version 3 of the License, or
48.11 - * (at your option) any later version.
48.12 - *
48.13 - * This program is distributed in the hope that it will be useful,
48.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
48.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48.16 - * GNU General Public License for more details.
48.17 - *
48.18 - * You should have received a copy of the GNU General Public License
48.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
48.20 - */
48.21 -package info.globalcode.sql.dk.configuration;
48.22 -
48.23 -import javax.xml.bind.annotation.XmlAttribute;
48.24 -import javax.xml.bind.annotation.XmlValue;
48.25 -
48.26 -/**
48.27 - * One configurable
48.28 - *
48.29 - * @author Ing. František Kučera (frantovo.cz)
48.30 - */
48.31 -public class Property implements NameIdentified, Cloneable {
48.32 -
48.33 - private String name;
48.34 - private String value;
48.35 -
48.36 - public Property() {
48.37 - }
48.38 -
48.39 - public Property(String name, String value) {
48.40 - this.name = name;
48.41 - this.value = value;
48.42 - }
48.43 -
48.44 - @XmlAttribute(name = "name")
48.45 - @Override
48.46 - public String getName() {
48.47 - return name;
48.48 - }
48.49 -
48.50 - public void setName(String name) {
48.51 - this.name = name;
48.52 - }
48.53 -
48.54 - @XmlValue
48.55 - public String getValue() {
48.56 - return value;
48.57 - }
48.58 -
48.59 - public void setValue(String value) {
48.60 - this.value = value;
48.61 - }
48.62 -
48.63 - @Override
48.64 - public String toString() {
48.65 - return name + "='" + value + "'";
48.66 - }
48.67 -
48.68 - @Override
48.69 - protected Property clone() {
48.70 - return new Property(name, value);
48.71 - }
48.72 -}
49.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/PropertyDeclaration.java Mon Mar 04 17:06:42 2019 +0100
49.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
49.3 @@ -1,57 +0,0 @@
49.4 -/**
49.5 - * SQL-DK
49.6 - * Copyright © 2015 František Kučera (frantovo.cz)
49.7 - *
49.8 - * This program is free software: you can redistribute it and/or modify
49.9 - * it under the terms of the GNU General Public License as published by
49.10 - * the Free Software Foundation, either version 3 of the License, or
49.11 - * (at your option) any later version.
49.12 - *
49.13 - * This program is distributed in the hope that it will be useful,
49.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
49.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49.16 - * GNU General Public License for more details.
49.17 - *
49.18 - * You should have received a copy of the GNU General Public License
49.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
49.20 - */
49.21 -package info.globalcode.sql.dk.configuration;
49.22 -
49.23 -import java.lang.annotation.ElementType;
49.24 -import java.lang.annotation.Repeatable;
49.25 -import java.lang.annotation.Retention;
49.26 -import static java.lang.annotation.RetentionPolicy.RUNTIME;
49.27 -import java.lang.annotation.Target;
49.28 -
49.29 -/**
49.30 - * Declaration of the (formatter) properties – for documentation purposes.
49.31 - *
49.32 - * TODO: automatically inject properties (configured, ad-hoc, default ones) to the formatters
49.33 - *
49.34 - * @author Ing. František Kučera (frantovo.cz)
49.35 - */
49.36 -@Retention(RUNTIME)
49.37 -@Target({ElementType.TYPE})
49.38 -@Repeatable(PropertyDeclarations.class)
49.39 -public @interface PropertyDeclaration {
49.40 -
49.41 - /**
49.42 - * @return name of the property
49.43 - */
49.44 - String name();
49.45 -
49.46 - /**
49.47 - * @return data type of the value: String, numbers, Boolean or Enum
49.48 - */
49.49 - Class type();
49.50 -
49.51 - /**
49.52 - * @return documentation for the users
49.53 - */
49.54 - String description();
49.55 -
49.56 - /**
49.57 - * @return default value of this property
49.58 - */
49.59 - String defaultValue();
49.60 -}
50.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/PropertyDeclarations.java Mon Mar 04 17:06:42 2019 +0100
50.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
50.3 @@ -1,35 +0,0 @@
50.4 -/**
50.5 - * SQL-DK
50.6 - * Copyright © 2015 František Kučera (frantovo.cz)
50.7 - *
50.8 - * This program is free software: you can redistribute it and/or modify
50.9 - * it under the terms of the GNU General Public License as published by
50.10 - * the Free Software Foundation, either version 3 of the License, or
50.11 - * (at your option) any later version.
50.12 - *
50.13 - * This program is distributed in the hope that it will be useful,
50.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
50.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50.16 - * GNU General Public License for more details.
50.17 - *
50.18 - * You should have received a copy of the GNU General Public License
50.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
50.20 - */
50.21 -package info.globalcode.sql.dk.configuration;
50.22 -
50.23 -import java.lang.annotation.ElementType;
50.24 -import java.lang.annotation.Retention;
50.25 -import static java.lang.annotation.RetentionPolicy.RUNTIME;
50.26 -import java.lang.annotation.Target;
50.27 -
50.28 -/**
50.29 - *
50.30 - * @author Ing. František Kučera (frantovo.cz)
50.31 - */
50.32 -@Retention(RUNTIME)
50.33 -@Target({ElementType.TYPE})
50.34 -public @interface PropertyDeclarations {
50.35 -
50.36 - PropertyDeclaration[] value();
50.37 -
50.38 -}
51.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/TunnelDefinition.java Mon Mar 04 17:06:42 2019 +0100
51.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
51.3 @@ -1,51 +0,0 @@
51.4 -/**
51.5 - * SQL-DK
51.6 - * Copyright © 2015 František Kučera (frantovo.cz)
51.7 - *
51.8 - * This program is free software: you can redistribute it and/or modify
51.9 - * it under the terms of the GNU General Public License as published by
51.10 - * the Free Software Foundation, either version 3 of the License, or
51.11 - * (at your option) any later version.
51.12 - *
51.13 - * This program is distributed in the hope that it will be useful,
51.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
51.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51.16 - * GNU General Public License for more details.
51.17 - *
51.18 - * You should have received a copy of the GNU General Public License
51.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
51.20 - */
51.21 -package info.globalcode.sql.dk.configuration;
51.22 -
51.23 -import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
51.24 -import java.util.List;
51.25 -import javax.xml.bind.annotation.XmlElement;
51.26 -
51.27 -/**
51.28 - *
51.29 - * @author Ing. František Kučera (frantovo.cz)
51.30 - */
51.31 -public class TunnelDefinition {
51.32 -
51.33 - private String command;
51.34 - private List<CommandArgument> arguments;
51.35 -
51.36 - @XmlElement(name = "command", namespace = CONFIGURATION)
51.37 - public String getCommand() {
51.38 - return command;
51.39 - }
51.40 -
51.41 - public void setCommand(String command) {
51.42 - this.command = command;
51.43 - }
51.44 -
51.45 - @XmlElement(name = "argument", namespace = CONFIGURATION)
51.46 - public List<CommandArgument> getArguments() {
51.47 - return arguments;
51.48 - }
51.49 -
51.50 - public void setArguments(List<CommandArgument> arguments) {
51.51 - this.arguments = arguments;
51.52 - }
51.53 -
51.54 -}
52.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/configuration/jaxb.index Mon Mar 04 17:06:42 2019 +0100
52.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
52.3 @@ -1,1 +0,0 @@
52.4 -Configuration
52.5 \ No newline at end of file
53.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractFormatter.java Mon Mar 04 17:06:42 2019 +0100
53.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
53.3 @@ -1,254 +0,0 @@
53.4 -/**
53.5 - * SQL-DK
53.6 - * Copyright © 2013 František Kučera (frantovo.cz)
53.7 - *
53.8 - * This program is free software: you can redistribute it and/or modify
53.9 - * it under the terms of the GNU General Public License as published by
53.10 - * the Free Software Foundation, either version 3 of the License, or
53.11 - * (at your option) any later version.
53.12 - *
53.13 - * This program is distributed in the hope that it will be useful,
53.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
53.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53.16 - * GNU General Public License for more details.
53.17 - *
53.18 - * You should have received a copy of the GNU General Public License
53.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
53.20 - */
53.21 -package info.globalcode.sql.dk.formatting;
53.22 -
53.23 -import info.globalcode.sql.dk.Parameter;
53.24 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
53.25 -import java.util.EmptyStackException;
53.26 -import java.util.EnumSet;
53.27 -import java.util.List;
53.28 -import java.util.Stack;
53.29 -
53.30 -/**
53.31 - * <ol>
53.32 - * <li>ensures integrity – if methods are called in correct order and context</li>
53.33 - * <li>provides default implmentations of methods that does not produce any output for given
53.34 - * events</li>
53.35 - * </ol>
53.36 - *
53.37 - * @author Ing. František Kučera (frantovo.cz)
53.38 - */
53.39 -public abstract class AbstractFormatter implements Formatter {
53.40 -
53.41 - private Stack<State> state = new Stack<>();
53.42 - private FormatterContext formatterContext;
53.43 - private ColumnsHeader currentColumnsHeader;
53.44 - private String currentQuery;
53.45 - private int currentColumnsCount;
53.46 - private int currentRowCount;
53.47 -
53.48 - public AbstractFormatter(FormatterContext formatterContext) {
53.49 - this.formatterContext = formatterContext;
53.50 - state.push(State.ROOT);
53.51 - }
53.52 -
53.53 - /*
53.54 - * root
53.55 - * .batch
53.56 - * ..database
53.57 - * ...statement
53.58 - * ....@query
53.59 - * ....@parameters
53.60 - * ....resultSet
53.61 - * .....row
53.62 - * ......@columnValue
53.63 - * ....@updatesResult
53.64 - */
53.65 - protected enum State {
53.66 -
53.67 - ROOT,
53.68 - BATCH,
53.69 - DATABASE,
53.70 - STATEMENT,
53.71 - RESULT_SET,
53.72 - ROW
53.73 - }
53.74 -
53.75 - /**
53.76 - * Go down in hierarchy.
53.77 - * Pushes new state and verifies the old one.
53.78 - *
53.79 - * @param current the new state – currently entering
53.80 - * @param expected expected previous states (any of them is valid)
53.81 - * @return previous state
53.82 - * @throws IllegalStateException if previous state was not one from expected
53.83 - */
53.84 - private State pushState(State current, EnumSet expected) {
53.85 - State previous = state.peek();
53.86 -
53.87 - if (expected.contains(previous)) {
53.88 - state.push(current);
53.89 - return previous;
53.90 - } else {
53.91 - throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected);
53.92 - }
53.93 - }
53.94 -
53.95 - protected State peekState(EnumSet expected) {
53.96 - State current = state.peek();
53.97 -
53.98 - if (expected.contains(current)) {
53.99 - return current;
53.100 - } else {
53.101 - throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected);
53.102 - }
53.103 -
53.104 - }
53.105 -
53.106 - /**
53.107 - * Go up in hierarchy.
53.108 - * Pops the superior state/branch.
53.109 - *
53.110 - * @param expected expected superior state
53.111 - * @return the superior state
53.112 - * @throws IllegalStateException if superior state was not one from expected or if there is no
53.113 - * more superior state (we are at root level)
53.114 - */
53.115 - private State popState(EnumSet expected) {
53.116 - try {
53.117 - state.pop();
53.118 - State superior = state.peek();
53.119 - if (expected.contains(superior)) {
53.120 - return superior;
53.121 - } else {
53.122 - throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected);
53.123 - }
53.124 - } catch (EmptyStackException e) {
53.125 - throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e);
53.126 - }
53.127 - }
53.128 -
53.129 - @Override
53.130 - public void writeStartBatch() {
53.131 - pushState(State.BATCH, EnumSet.of(State.ROOT));
53.132 - }
53.133 -
53.134 - @Override
53.135 - public void writeEndBatch() {
53.136 - popState(EnumSet.of(State.ROOT));
53.137 - }
53.138 -
53.139 - @Override
53.140 - public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
53.141 - pushState(State.DATABASE, EnumSet.of(State.BATCH));
53.142 - }
53.143 -
53.144 - @Override
53.145 - public void writeEndDatabase() {
53.146 - popState(EnumSet.of(State.BATCH));
53.147 - }
53.148 -
53.149 - @Override
53.150 - public void writeStartStatement() {
53.151 - pushState(State.STATEMENT, EnumSet.of(State.DATABASE));
53.152 - }
53.153 -
53.154 - @Override
53.155 - public void writeEndStatement() {
53.156 - popState(EnumSet.of(State.DATABASE));
53.157 - }
53.158 -
53.159 - @Override
53.160 - public void writeStartResultSet(ColumnsHeader header) {
53.161 - pushState(State.RESULT_SET, EnumSet.of(State.STATEMENT));
53.162 - currentRowCount = 0;
53.163 - currentColumnsHeader = header;
53.164 - }
53.165 -
53.166 - @Override
53.167 - public void writeEndResultSet() {
53.168 - popState(EnumSet.of(State.STATEMENT));
53.169 - currentColumnsHeader = null;
53.170 - }
53.171 -
53.172 - @Override
53.173 - public void writeQuery(String sql) {
53.174 - peekState(EnumSet.of(State.STATEMENT));
53.175 -
53.176 - if (currentColumnsHeader == null) {
53.177 - currentQuery = sql;
53.178 - } else {
53.179 - throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader);
53.180 - }
53.181 - }
53.182 -
53.183 - @Override
53.184 - public void writeParameters(List<? extends Parameter> parameters) {
53.185 - peekState(EnumSet.of(State.STATEMENT));
53.186 -
53.187 - if (currentColumnsHeader != null) {
53.188 - throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader);
53.189 - }
53.190 -
53.191 - if (currentQuery == null && parameters != null) {
53.192 - throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set.");
53.193 - }
53.194 - }
53.195 -
53.196 - @Override
53.197 - public void writeStartRow() {
53.198 - pushState(State.ROW, EnumSet.of(State.RESULT_SET));
53.199 - currentColumnsCount = 0;
53.200 - currentRowCount++;
53.201 - }
53.202 -
53.203 - @Override
53.204 - public void writeEndRow() {
53.205 - popState(EnumSet.of(State.RESULT_SET));
53.206 - }
53.207 -
53.208 - @Override
53.209 - public void writeColumnValue(Object value) {
53.210 - peekState(EnumSet.of(State.ROW));
53.211 - currentColumnsCount++;
53.212 -
53.213 - int declaredCount = currentColumnsHeader.getColumnCount();
53.214 - if (currentColumnsCount > declaredCount) {
53.215 - throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header.");
53.216 - }
53.217 - }
53.218 -
53.219 - @Override
53.220 - public void writeUpdatesResult(int updatedRowsCount) {
53.221 - peekState(EnumSet.of(State.STATEMENT));
53.222 - }
53.223 -
53.224 - @Override
53.225 - public void close() throws FormatterException {
53.226 - }
53.227 -
53.228 - public FormatterContext getFormatterContext() {
53.229 - return formatterContext;
53.230 - }
53.231 -
53.232 - protected ColumnsHeader getCurrentColumnsHeader() {
53.233 - return currentColumnsHeader;
53.234 - }
53.235 -
53.236 - /**
53.237 - * @return column number, 1 = first
53.238 - */
53.239 - protected int getCurrentColumnsCount() {
53.240 - return currentColumnsCount;
53.241 - }
53.242 -
53.243 - protected boolean isCurrentColumnFirst() {
53.244 - return currentColumnsCount == 1;
53.245 - }
53.246 -
53.247 - protected boolean isCurrentColumnLast() {
53.248 - return currentColumnsCount == currentColumnsHeader.getColumnCount();
53.249 - }
53.250 -
53.251 - /**
53.252 - * @return row number, 1 = first
53.253 - */
53.254 - protected int getCurrentRowCount() {
53.255 - return currentRowCount;
53.256 - }
53.257 -}
54.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/AbstractXmlFormatter.java Mon Mar 04 17:06:42 2019 +0100
54.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
54.3 @@ -1,241 +0,0 @@
54.4 -/**
54.5 - * SQL-DK
54.6 - * Copyright © 2014 František Kučera (frantovo.cz)
54.7 - *
54.8 - * This program is free software: you can redistribute it and/or modify
54.9 - * it under the terms of the GNU General Public License as published by
54.10 - * the Free Software Foundation, either version 3 of the License, or
54.11 - * (at your option) any later version.
54.12 - *
54.13 - * This program is distributed in the hope that it will be useful,
54.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
54.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54.16 - * GNU General Public License for more details.
54.17 - *
54.18 - * You should have received a copy of the GNU General Public License
54.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
54.20 - */
54.21 -package info.globalcode.sql.dk.formatting;
54.22 -
54.23 -import info.globalcode.sql.dk.ColorfulPrintWriter;
54.24 -import info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
54.25 -import java.util.Stack;
54.26 -import javax.xml.namespace.QName;
54.27 -import static info.globalcode.sql.dk.Functions.isEmpty;
54.28 -import static info.globalcode.sql.dk.Functions.toHex;
54.29 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
54.30 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
54.31 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
54.32 -import java.nio.charset.Charset;
54.33 -import java.util.EmptyStackException;
54.34 -import java.util.HashMap;
54.35 -import java.util.LinkedHashMap;
54.36 -import java.util.Map;
54.37 -import java.util.Map.Entry;
54.38 -import java.util.logging.Level;
54.39 -import java.util.logging.Logger;
54.40 -
54.41 -/**
54.42 - * <p>
54.43 - * Provides helper methods for printing pretty intended and optionally colorful (syntax highlighted)
54.44 - * XML output.
54.45 - * </p>
54.46 - *
54.47 - * <p>
54.48 - * Must be used with care – bad usage can lead to invalid XML (e.g. using undeclared namespaces).
54.49 - * </p>
54.50 - *
54.51 - * @author Ing. František Kučera (frantovo.cz)
54.52 - */
54.53 -@PropertyDeclaration(name = COLORFUL, defaultValue = "false", type = Boolean.class, description = COLORFUL_DESCRIPTION)
54.54 -@PropertyDeclaration(name = AbstractXmlFormatter.PROPERTY_INDENT, defaultValue = AbstractXmlFormatter.PROPERTY_INDENT_DEFAULT, type = String.class, description = "tab or sequence of spaces used for indentation of nested elements")
54.55 -@PropertyDeclaration(name = AbstractXmlFormatter.PROPERTY_INDENT_TEXT, defaultValue = "true", type = Boolean.class, description = "whether text with line breaks should be indented; if not original whitespace will be preserved.")
54.56 -public abstract class AbstractXmlFormatter extends AbstractFormatter {
54.57 -
54.58 - private static final Logger log = Logger.getLogger(AbstractXmlFormatter.class.getName());
54.59 - public static final String PROPERTY_INDENT = "indent";
54.60 - protected static final String PROPERTY_INDENT_DEFAULT = "\t";
54.61 - public static final String PROPERTY_INDENT_TEXT = "indentText";
54.62 - private static final TerminalColor ELEMENT_COLOR = TerminalColor.Magenta;
54.63 - private static final TerminalColor ATTRIBUTE_NAME_COLOR = TerminalColor.Green;
54.64 - private static final TerminalColor ATTRIBUTE_VALUE_COLOR = TerminalColor.Yellow;
54.65 - private static final TerminalColor XML_DECLARATION_COLOR = TerminalColor.Red;
54.66 - private static final TerminalColor XML_DOCTYPE_COLOR = TerminalColor.Cyan;
54.67 - private Stack<QName> treePosition = new Stack<>();
54.68 - private final ColorfulPrintWriter out;
54.69 - private final String indent;
54.70 - private final boolean indentText;
54.71 -
54.72 - public AbstractXmlFormatter(FormatterContext formatterContext) {
54.73 - super(formatterContext);
54.74 - boolean colorful = formatterContext.getProperties().getBoolean(COLORFUL, false);
54.75 - out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
54.76 - indent = formatterContext.getProperties().getString(PROPERTY_INDENT, PROPERTY_INDENT_DEFAULT);
54.77 - indentText = formatterContext.getProperties().getBoolean(PROPERTY_INDENT_TEXT, true);
54.78 -
54.79 - if (!indent.matches("\\s*")) {
54.80 - log.log(Level.WARNING, "Setting indent to „{0}“ is weird & freaky; in hex: {1}", new Object[]{indent, toHex(indent.getBytes())});
54.81 - }
54.82 -
54.83 - }
54.84 -
54.85 - protected void printStartDocument() {
54.86 - out.print(XML_DECLARATION_COLOR, "<?xml version=\"1.0\" encoding=\"" + Charset.defaultCharset().name() + "\"?>");
54.87 - }
54.88 -
54.89 - protected void printDoctype(String doctype) {
54.90 - out.print(XML_DOCTYPE_COLOR, "\n<!DOCTYPE " + doctype + ">");
54.91 - }
54.92 -
54.93 - protected void printEndDocument() {
54.94 - out.println();
54.95 - out.flush();
54.96 - if (!treePosition.empty()) {
54.97 - throw new IllegalStateException("Some elements are not closed: " + treePosition);
54.98 - }
54.99 - }
54.100 -
54.101 - protected void printStartElement(QName element) {
54.102 - printStartElement(element, null);
54.103 - }
54.104 -
54.105 - protected Map<QName, String> singleAttribute(QName name, String value) {
54.106 - Map<QName, String> attributes = new HashMap<>(2);
54.107 - attributes.put(name, value);
54.108 - return attributes;
54.109 - }
54.110 -
54.111 - protected void printStartElement(QName element, Map<QName, String> attributes) {
54.112 - printStartElement(element, attributes, false);
54.113 - }
54.114 -
54.115 - /**
54.116 - * @param empty whether element should be closed <codfe>… /></code> (has no content, do not
54.117 - * call {@linkplain #printEndElement()})
54.118 - */
54.119 - private void printStartElement(QName element, Map<QName, String> attributes, boolean empty) {
54.120 - printIndent();
54.121 -
54.122 - out.print(ELEMENT_COLOR, "<" + toString(element));
54.123 -
54.124 - if (attributes != null) {
54.125 - for (Entry<QName, String> attribute : attributes.entrySet()) {
54.126 - out.print(" ");
54.127 - out.print(ATTRIBUTE_NAME_COLOR, toString(attribute.getKey()));
54.128 - out.print("=");
54.129 - out.print(ATTRIBUTE_VALUE_COLOR, '"' + escapeXmlAttribute(attribute.getValue()) + '"');
54.130 - }
54.131 - }
54.132 -
54.133 - if (empty) {
54.134 - out.print(ELEMENT_COLOR, "/>");
54.135 - } else {
54.136 - out.print(ELEMENT_COLOR, ">");
54.137 - treePosition.add(element);
54.138 - }
54.139 -
54.140 - out.flush();
54.141 - }
54.142 -
54.143 - /**
54.144 - * Prints text node wrapped in given element without indenting the text and adding line breaks
54.145 - * (useful for short texts).
54.146 - *
54.147 - * @param attributes use {@linkplain LinkedHashMap} to preserve attributes order
54.148 - */
54.149 - protected void printTextElement(QName element, Map<QName, String> attributes, String text) {
54.150 - printStartElement(element, attributes);
54.151 -
54.152 - String[] lines = text.split("\\n");
54.153 -
54.154 - if (indentText && lines.length > 1) {
54.155 - for (String line : lines) {
54.156 - printText(line, true);
54.157 - }
54.158 - printEndElement(true);
54.159 - } else {
54.160 - /*
54.161 - * line breaks at the end of the text will be eaten – if you need them, use indentText = false
54.162 - */
54.163 - if (lines.length == 1 && text.endsWith("\n")) {
54.164 - text = text.substring(0, text.length() - 1);
54.165 - }
54.166 -
54.167 - printText(text, false);
54.168 - printEndElement(false);
54.169 - }
54.170 - }
54.171 -
54.172 - protected void printEmptyElement(QName element, Map<QName, String> attributes) {
54.173 - printStartElement(element, attributes, true);
54.174 - }
54.175 -
54.176 - protected void printEndElement() {
54.177 - printEndElement(true);
54.178 - }
54.179 -
54.180 - private void printEndElement(boolean indent) {
54.181 - try {
54.182 - QName name = treePosition.pop();
54.183 -
54.184 - if (indent) {
54.185 - printIndent();
54.186 - }
54.187 -
54.188 - out.print(ELEMENT_COLOR, "</" + toString(name) + ">");
54.189 - out.flush();
54.190 -
54.191 - } catch (EmptyStackException e) {
54.192 - throw new IllegalStateException("No more elements to end.", e);
54.193 - }
54.194 - }
54.195 -
54.196 - protected void printText(String s, boolean indent) {
54.197 - if (indent) {
54.198 - printIndent();
54.199 - }
54.200 - out.print(escapeXmlText(s));
54.201 - out.flush();
54.202 - }
54.203 -
54.204 - protected void printIndent() {
54.205 - out.println();
54.206 - for (int i = 0; i < treePosition.size(); i++) {
54.207 - out.print(indent);
54.208 - }
54.209 - }
54.210 -
54.211 - protected static QName qname(String name) {
54.212 - return new QName(name);
54.213 - }
54.214 -
54.215 - protected static QName qname(String prefix, String name) {
54.216 - return new QName(null, name, prefix);
54.217 - }
54.218 -
54.219 - private String toString(QName name) {
54.220 - if (isEmpty(name.getPrefix(), true)) {
54.221 - return escapeName(name.getLocalPart());
54.222 - } else {
54.223 - return escapeName(name.getPrefix()) + ":" + escapeName(name.getLocalPart());
54.224 - }
54.225 - }
54.226 -
54.227 - private String escapeName(String s) {
54.228 - // TODO: avoid ugly values in <name name="…"/>
54.229 - return s;
54.230 - }
54.231 -
54.232 - private static String escapeXmlText(String s) {
54.233 - return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
54.234 - // Not needed:
54.235 - // return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
54.236 - }
54.237 -
54.238 - /**
54.239 - * Expects attribute values enclosed in "quotes" not 'apostrophes'.
54.240 - */
54.241 - private static String escapeXmlAttribute(String s) {
54.242 - return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
54.243 - }
54.244 -}
55.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/BarChartFormatter.java Mon Mar 04 17:06:42 2019 +0100
55.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
55.3 @@ -1,104 +0,0 @@
55.4 -/**
55.5 - * SQL-DK
55.6 - * Copyright © 2015 František Kučera (frantovo.cz)
55.7 - *
55.8 - * This program is free software: you can redistribute it and/or modify
55.9 - * it under the terms of the GNU General Public License as published by
55.10 - * the Free Software Foundation, either version 3 of the License, or
55.11 - * (at your option) any later version.
55.12 - *
55.13 - * This program is distributed in the hope that it will be useful,
55.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
55.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55.16 - * GNU General Public License for more details.
55.17 - *
55.18 - * You should have received a copy of the GNU General Public License
55.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
55.20 - */
55.21 -package info.globalcode.sql.dk.formatting;
55.22 -
55.23 -import info.globalcode.sql.dk.Functions;
55.24 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
55.25 -import info.globalcode.sql.dk.logging.LoggerProducer;
55.26 -import java.math.BigDecimal;
55.27 -import java.math.MathContext;
55.28 -import java.math.RoundingMode;
55.29 -import java.util.List;
55.30 -import java.util.logging.Level;
55.31 -import java.util.logging.Logger;
55.32 -
55.33 -/**
55.34 - * TODO: min/max values – range for case that no value is 100 %
55.35 - *
55.36 - * TODO: multiple barcharts in same table (last column is still default) + multiple resultsets
55.37 - *
55.38 - * TODO: negative values - bar starting from the middle, not always from the left
55.39 - *
55.40 - * @author Ing. František Kučera (frantovo.cz)
55.41 - */
55.42 -@PropertyDeclaration(name = BarChartFormatter.PROPERTY_PRECISION, type = Integer.class, defaultValue = BarChartFormatter.PROPERTY_PRECISION_DEFAULT, description = "number of characters representing 100 % in the bar chart")
55.43 -public class BarChartFormatter extends TabularPrefetchingFormatter {
55.44 -
55.45 - public static final String NAME = "barchart"; // bash-completion:formatter
55.46 - public static final String PROPERTY_PRECISION = "precision";
55.47 - protected static final String PROPERTY_PRECISION_DEFAULT = "100";
55.48 - private static final MathContext mathContext = MathContext.DECIMAL128;
55.49 - public static final Logger log = LoggerProducer.getLogger();
55.50 - private final BigDecimal chartPrecision;
55.51 - private final char chartFull;
55.52 - private final char chartEmpty;
55.53 -
55.54 - public BarChartFormatter(FormatterContext formatterContext) {
55.55 - super(formatterContext);
55.56 - chartPrecision = BigDecimal.valueOf(formatterContext.getProperties().getInteger(PROPERTY_PRECISION, Integer.parseInt(PROPERTY_PRECISION_DEFAULT)));
55.57 - chartFull = isAsciiNostalgia() ? '#' : '█';
55.58 - chartEmpty = isAsciiNostalgia() ? '~' : '░';
55.59 - // TODO: consider using partial blocks for more precision: https://en.wikipedia.org/wiki/Block_Elements
55.60 - }
55.61 -
55.62 - @Override
55.63 - protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
55.64 - super.postprocessPrefetchedResultSet(currentHeader, currentResultSet);
55.65 -
55.66 - updateColumnWidth(currentHeader.getColumnCount(), chartPrecision.intValue());
55.67 -
55.68 - BigDecimal maximum = BigDecimal.ZERO;
55.69 - BigDecimal minimum = BigDecimal.ZERO;
55.70 - int lastIndex = currentHeader.getColumnCount() - 1;
55.71 -
55.72 - Object valueObject = null;
55.73 - try {
55.74 - for (Object[] row : currentResultSet) {
55.75 - valueObject = row[lastIndex];
55.76 - if (valueObject != null) {
55.77 - BigDecimal value = new BigDecimal(valueObject.toString());
55.78 - maximum = maximum.max(value);
55.79 - minimum = minimum.min(value);
55.80 - }
55.81 - }
55.82 -
55.83 - BigDecimal range = maximum.subtract(minimum);
55.84 -
55.85 - for (Object[] row : currentResultSet) {
55.86 - valueObject = row[lastIndex];
55.87 - if (valueObject == null) {
55.88 - row[lastIndex] = "";
55.89 - } else {
55.90 - BigDecimal value = new BigDecimal(valueObject.toString());
55.91 - BigDecimal valueFromMinimum = value.subtract(minimum);
55.92 -
55.93 - BigDecimal points = chartPrecision.divide(range, mathContext).multiply(valueFromMinimum, mathContext);
55.94 - int pointsRounded = points.setScale(0, RoundingMode.HALF_UP).intValue();
55.95 - row[lastIndex] = Functions.repeat(chartFull, pointsRounded) + Functions.repeat(chartEmpty, chartPrecision.intValue() - pointsRounded);
55.96 - }
55.97 - }
55.98 -
55.99 - } catch (NumberFormatException e) {
55.100 - // https://en.wiktionary.org/wiki/parsable
55.101 - log.log(Level.SEVERE, "Last column must be number or an object with toString() value parsable to a number. But was „{0}“", valueObject);
55.102 - // FIXME: throw FormatterException
55.103 - throw e;
55.104 - }
55.105 - }
55.106 -
55.107 -}
56.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnDescriptor.java Mon Mar 04 17:06:42 2019 +0100
56.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
56.3 @@ -1,122 +0,0 @@
56.4 -/**
56.5 - * SQL-DK
56.6 - * Copyright © 2013 František Kučera (frantovo.cz)
56.7 - *
56.8 - * This program is free software: you can redistribute it and/or modify
56.9 - * it under the terms of the GNU General Public License as published by
56.10 - * the Free Software Foundation, either version 3 of the License, or
56.11 - * (at your option) any later version.
56.12 - *
56.13 - * This program is distributed in the hope that it will be useful,
56.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
56.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56.16 - * GNU General Public License for more details.
56.17 - *
56.18 - * You should have received a copy of the GNU General Public License
56.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
56.20 - */
56.21 -package info.globalcode.sql.dk.formatting;
56.22 -
56.23 -import java.sql.Types;
56.24 -
56.25 -/**
56.26 - *
56.27 - * @author Ing. František Kučera (frantovo.cz)
56.28 - */
56.29 -public class ColumnDescriptor {
56.30 -
56.31 - private String name;
56.32 - private String label;
56.33 - private int type;
56.34 - private String typeName;
56.35 - private boolean firstColumn;
56.36 - private boolean lastColumn;
56.37 - private int columnNumber;
56.38 -
56.39 - /**
56.40 - * @return column name
56.41 - * @see #getLabel()
56.42 - */
56.43 - public String getName() {
56.44 - return name;
56.45 - }
56.46 -
56.47 - public void setName(String name) {
56.48 - this.name = name;
56.49 - }
56.50 -
56.51 - /**
56.52 - * @return label specified by the SQL AS clause
56.53 - */
56.54 - public String getLabel() {
56.55 - return label;
56.56 - }
56.57 -
56.58 - public void setLabel(String label) {
56.59 - this.label = label;
56.60 - }
56.61 -
56.62 - public int getType() {
56.63 - return type;
56.64 - }
56.65 -
56.66 - public void setType(int type) {
56.67 - this.type = type;
56.68 - }
56.69 -
56.70 - public String getTypeName() {
56.71 - return typeName;
56.72 - }
56.73 -
56.74 - public void setTypeName(String typeName) {
56.75 - this.typeName = typeName;
56.76 - }
56.77 -
56.78 - public boolean isFirstColumn() {
56.79 - return firstColumn;
56.80 - }
56.81 -
56.82 - public void setFirstColumn(boolean firstColumn) {
56.83 - this.firstColumn = firstColumn;
56.84 - }
56.85 -
56.86 - public boolean isLastColumn() {
56.87 - return lastColumn;
56.88 - }
56.89 -
56.90 - public void setLastColumn(boolean lastColumn) {
56.91 - this.lastColumn = lastColumn;
56.92 - }
56.93 -
56.94 - /**
56.95 - * @return number of this column, 1 = first
56.96 - */
56.97 - public int getColumnNumber() {
56.98 - return columnNumber;
56.99 - }
56.100 -
56.101 - public void setColumnNumber(int columnNumber) {
56.102 - this.columnNumber = columnNumber;
56.103 - }
56.104 -
56.105 - public boolean isBoolean() {
56.106 - return type == Types.BOOLEAN;
56.107 - }
56.108 -
56.109 - public boolean isNumeric() {
56.110 - switch (type) {
56.111 - case Types.BIGINT:
56.112 - case Types.DECIMAL:
56.113 - case Types.DOUBLE:
56.114 - case Types.FLOAT:
56.115 - case Types.INTEGER:
56.116 - case Types.NUMERIC:
56.117 - case Types.REAL:
56.118 - case Types.SMALLINT:
56.119 - case Types.TINYINT:
56.120 - return true;
56.121 - default:
56.122 - return false;
56.123 - }
56.124 - }
56.125 -}
57.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/ColumnsHeader.java Mon Mar 04 17:06:42 2019 +0100
57.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
57.3 @@ -1,70 +0,0 @@
57.4 -/**
57.5 - * SQL-DK
57.6 - * Copyright © 2013 František Kučera (frantovo.cz)
57.7 - *
57.8 - * This program is free software: you can redistribute it and/or modify
57.9 - * it under the terms of the GNU General Public License as published by
57.10 - * the Free Software Foundation, either version 3 of the License, or
57.11 - * (at your option) any later version.
57.12 - *
57.13 - * This program is distributed in the hope that it will be useful,
57.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
57.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57.16 - * GNU General Public License for more details.
57.17 - *
57.18 - * You should have received a copy of the GNU General Public License
57.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
57.20 - */
57.21 -package info.globalcode.sql.dk.formatting;
57.22 -
57.23 -import java.sql.ResultSetMetaData;
57.24 -import java.sql.SQLException;
57.25 -import java.util.ArrayList;
57.26 -import java.util.List;
57.27 -
57.28 -/**
57.29 - *
57.30 - * @author Ing. František Kučera (frantovo.cz)
57.31 - */
57.32 -public class ColumnsHeader {
57.33 -
57.34 - private ResultSetMetaData metaData;
57.35 -
57.36 - public ColumnsHeader(ResultSetMetaData metaData) {
57.37 - this.metaData = metaData;
57.38 - }
57.39 -
57.40 - public int getColumnCount() {
57.41 - try {
57.42 - return metaData.getColumnCount();
57.43 - } catch (SQLException e) {
57.44 - throw new IllegalStateException("Error during getting column count.", e);
57.45 - }
57.46 - }
57.47 -
57.48 - public List<ColumnDescriptor> getColumnDescriptors() {
57.49 - try {
57.50 - int count = metaData.getColumnCount();
57.51 - List<ColumnDescriptor> list = new ArrayList<>(count);
57.52 -
57.53 - for (int i = 1; i <= count; i++) {
57.54 - ColumnDescriptor cd = new ColumnDescriptor();
57.55 -
57.56 - cd.setFirstColumn(i == 1);
57.57 - cd.setLastColumn(i == count);
57.58 - cd.setColumnNumber(i);
57.59 -
57.60 - cd.setLabel(metaData.getColumnLabel(i));
57.61 - cd.setName(metaData.getColumnName(i));
57.62 - cd.setType(metaData.getColumnType(i));
57.63 - cd.setTypeName(metaData.getColumnTypeName(i));
57.64 - /** TODO: more properties */
57.65 - list.add(cd);
57.66 - }
57.67 -
57.68 - return list;
57.69 - } catch (SQLException e) {
57.70 - throw new IllegalStateException("Error during building column descriptors.", e);
57.71 - }
57.72 - }
57.73 -}
58.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/CommonProperties.java Mon Mar 04 17:06:42 2019 +0100
58.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
58.3 @@ -1,50 +0,0 @@
58.4 -/**
58.5 - * SQL-DK
58.6 - * Copyright © 2015 František Kučera (frantovo.cz)
58.7 - *
58.8 - * This program is free software: you can redistribute it and/or modify
58.9 - * it under the terms of the GNU General Public License as published by
58.10 - * the Free Software Foundation, either version 3 of the License, or
58.11 - * (at your option) any later version.
58.12 - *
58.13 - * This program is distributed in the hope that it will be useful,
58.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
58.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58.16 - * GNU General Public License for more details.
58.17 - *
58.18 - * You should have received a copy of the GNU General Public License
58.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
58.20 - */
58.21 -package info.globalcode.sql.dk.formatting;
58.22 -
58.23 -import java.util.Collections;
58.24 -import java.util.HashMap;
58.25 -import java.util.Map;
58.26 -
58.27 -/**
58.28 - *
58.29 - * @author Ing. František Kučera (frantovo.cz)
58.30 - */
58.31 -public class CommonProperties {
58.32 -
58.33 - private static final Map<Class, String> TYPE_SIMPLE_NAMES;
58.34 -
58.35 - static {
58.36 - Map<Class, String> m = new HashMap<>();
58.37 - m.put(Boolean.class, "boolean");
58.38 - m.put(String.class, "String");
58.39 - m.put(Character.class, "char");
58.40 - m.put(Integer.class, "int");
58.41 - m.put(Long.class, "long");
58.42 - m.put(Double.class, "double");
58.43 - TYPE_SIMPLE_NAMES = Collections.unmodifiableMap(m);
58.44 - }
58.45 -
58.46 - public static String getSimpleTypeName(Class type) {
58.47 - String name = TYPE_SIMPLE_NAMES.get(type);
58.48 - return name == null ? type.getName() : name;
58.49 - }
58.50 -
58.51 - public static final String COLORFUL = "color";
58.52 - public static final String COLORFUL_DESCRIPTION = "whether the output should be printed in color (ANSI Escape Sequences)";
58.53 -}
59.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/FakeSqlArray.java Mon Mar 04 17:06:42 2019 +0100
59.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
59.3 @@ -1,106 +0,0 @@
59.4 -/**
59.5 - * SQL-DK
59.6 - * Copyright © 2014 František Kučera (frantovo.cz)
59.7 - *
59.8 - * This program is free software: you can redistribute it and/or modify
59.9 - * it under the terms of the GNU General Public License as published by
59.10 - * the Free Software Foundation, either version 3 of the License, or
59.11 - * (at your option) any later version.
59.12 - *
59.13 - * This program is distributed in the hope that it will be useful,
59.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
59.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59.16 - * GNU General Public License for more details.
59.17 - *
59.18 - * You should have received a copy of the GNU General Public License
59.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
59.20 - */
59.21 -package info.globalcode.sql.dk.formatting;
59.22 -
59.23 -import info.globalcode.sql.dk.SQLType;
59.24 -import java.sql.Array;
59.25 -import java.sql.ResultSet;
59.26 -import java.sql.SQLException;
59.27 -import java.util.Map;
59.28 -
59.29 -/**
59.30 - * Fake SQL array, for formatting purposes only
59.31 - *
59.32 - * @author Ing. František Kučera (frantovo.cz)
59.33 - */
59.34 -public class FakeSqlArray implements Array {
59.35 -
59.36 - private static final UnsupportedOperationException exception = new UnsupportedOperationException("This is just a fake SQL array.");
59.37 - private final Object[] data;
59.38 - private final SQLType baseType;
59.39 -
59.40 - public FakeSqlArray(Object[] data, SQLType baseType) {
59.41 - this.data = data;
59.42 - this.baseType = baseType;
59.43 - }
59.44 -
59.45 - @Override
59.46 - public String toString() {
59.47 - StringBuilder string = new StringBuilder();
59.48 - for (Object o : data) {
59.49 - string.append(o);
59.50 - string.append("\n");
59.51 - }
59.52 - return string.toString();
59.53 - }
59.54 -
59.55 - @Override
59.56 - public String getBaseTypeName() throws SQLException {
59.57 - return baseType.name();
59.58 - }
59.59 -
59.60 - @Override
59.61 - public int getBaseType() throws SQLException {
59.62 - return baseType.getCode();
59.63 - }
59.64 -
59.65 - @Override
59.66 - public Object getArray() throws SQLException {
59.67 - return data;
59.68 - }
59.69 -
59.70 - @Override
59.71 - public Object getArray(Map<String, Class<?>> map) throws SQLException {
59.72 - throw exception;
59.73 - }
59.74 -
59.75 - @Override
59.76 - public Object getArray(long index, int count) throws SQLException {
59.77 - throw exception;
59.78 - }
59.79 -
59.80 - @Override
59.81 - public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
59.82 - throw exception;
59.83 - }
59.84 -
59.85 - @Override
59.86 - public ResultSet getResultSet() throws SQLException {
59.87 - throw exception;
59.88 - }
59.89 -
59.90 - @Override
59.91 - public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
59.92 - throw exception;
59.93 - }
59.94 -
59.95 - @Override
59.96 - public ResultSet getResultSet(long index, int count) throws SQLException {
59.97 - throw exception;
59.98 - }
59.99 -
59.100 - @Override
59.101 - public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map) throws SQLException {
59.102 - throw exception;
59.103 - }
59.104 -
59.105 - @Override
59.106 - public void free() throws SQLException {
59.107 - throw exception;
59.108 - }
59.109 -}
60.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/Formatter.java Mon Mar 04 17:06:42 2019 +0100
60.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
60.3 @@ -1,67 +0,0 @@
60.4 -/**
60.5 - * SQL-DK
60.6 - * Copyright © 2013 František Kučera (frantovo.cz)
60.7 - *
60.8 - * This program is free software: you can redistribute it and/or modify
60.9 - * it under the terms of the GNU General Public License as published by
60.10 - * the Free Software Foundation, either version 3 of the License, or
60.11 - * (at your option) any later version.
60.12 - *
60.13 - * This program is distributed in the hope that it will be useful,
60.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
60.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60.16 - * GNU General Public License for more details.
60.17 - *
60.18 - * You should have received a copy of the GNU General Public License
60.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
60.20 - */
60.21 -package info.globalcode.sql.dk.formatting;
60.22 -
60.23 -import info.globalcode.sql.dk.Parameter;
60.24 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
60.25 -import java.util.List;
60.26 -
60.27 -/**
60.28 - * The formatter is responsible for printing the result sets and/or updates result (count of
60.29 - * inserted/updated rows). The formatter can produce output in arbitrary format – text, some markup
60.30 - * or even binary data.
60.31 - *
60.32 - * @author Ing. František Kučera (frantovo.cz)
60.33 - */
60.34 -public interface Formatter extends AutoCloseable {
60.35 -
60.36 - void writeStartBatch();
60.37 -
60.38 - void writeStartDatabase(DatabaseDefinition databaseDefinition);
60.39 -
60.40 - void writeEndDatabase();
60.41 -
60.42 - void writeStartStatement();
60.43 -
60.44 - void writeEndStatement();
60.45 -
60.46 - void writeQuery(String sql);
60.47 -
60.48 - void writeParameters(List<? extends Parameter> parameters);
60.49 -
60.50 - void writeStartResultSet(ColumnsHeader header);
60.51 -
60.52 - void writeEndResultSet();
60.53 -
60.54 - void writeStartRow();
60.55 -
60.56 - void writeColumnValue(Object value);
60.57 -
60.58 - void writeEndRow();
60.59 -
60.60 - void writeUpdatesResult(int updatedRowsCount);
60.61 -
60.62 - void writeEndBatch();
60.63 -
60.64 - /**
60.65 - * If an error occurs (e.g. lost connection during result set reading) this method will be
60.66 - * called even if there was no {@linkplain #writeEndBach()}.
60.67 - */
60.68 - @Override
60.69 - void close() throws FormatterException;
60.70 -}
61.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/FormatterContext.java Mon Mar 04 17:06:42 2019 +0100
61.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
61.3 @@ -1,49 +0,0 @@
61.4 -/**
61.5 - * SQL-DK
61.6 - * Copyright © 2013 František Kučera (frantovo.cz)
61.7 - *
61.8 - * This program is free software: you can redistribute it and/or modify
61.9 - * it under the terms of the GNU General Public License as published by
61.10 - * the Free Software Foundation, either version 3 of the License, or
61.11 - * (at your option) any later version.
61.12 - *
61.13 - * This program is distributed in the hope that it will be useful,
61.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
61.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61.16 - * GNU General Public License for more details.
61.17 - *
61.18 - * You should have received a copy of the GNU General Public License
61.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
61.20 - */
61.21 -package info.globalcode.sql.dk.formatting;
61.22 -
61.23 -import info.globalcode.sql.dk.configuration.Properties;
61.24 -import java.io.OutputStream;
61.25 -
61.26 -/**
61.27 - * To be passed from the SQL-DK core to the formatter.
61.28 - *
61.29 - * @author Ing. František Kučera (frantovo.cz)
61.30 - */
61.31 -public class FormatterContext {
61.32 -
61.33 - private OutputStream outputStream;
61.34 - private Properties properties;
61.35 -
61.36 - public FormatterContext(OutputStream outputStream, Properties properties) {
61.37 - this.outputStream = outputStream;
61.38 - this.properties = properties;
61.39 - }
61.40 -
61.41 - public OutputStream getOutputStream() {
61.42 - return outputStream;
61.43 - }
61.44 -
61.45 - public Properties getProperties() {
61.46 - return properties;
61.47 - }
61.48 -
61.49 - public void setProperties(Properties properties) {
61.50 - this.properties = properties;
61.51 - }
61.52 -}
62.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/FormatterException.java Mon Mar 04 17:06:42 2019 +0100
62.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
62.3 @@ -1,42 +0,0 @@
62.4 -/**
62.5 - * SQL-DK
62.6 - * Copyright © 2013 František Kučera (frantovo.cz)
62.7 - *
62.8 - * This program is free software: you can redistribute it and/or modify
62.9 - * it under the terms of the GNU General Public License as published by
62.10 - * the Free Software Foundation, either version 3 of the License, or
62.11 - * (at your option) any later version.
62.12 - *
62.13 - * This program is distributed in the hope that it will be useful,
62.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
62.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62.16 - * GNU General Public License for more details.
62.17 - *
62.18 - * You should have received a copy of the GNU General Public License
62.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
62.20 - */
62.21 -package info.globalcode.sql.dk.formatting;
62.22 -
62.23 -import info.globalcode.sql.dk.DKException;
62.24 -
62.25 -/**
62.26 - *
62.27 - * @author Ing. František Kučera (frantovo.cz)
62.28 - */
62.29 -public class FormatterException extends DKException {
62.30 -
62.31 - public FormatterException() {
62.32 - }
62.33 -
62.34 - public FormatterException(String message) {
62.35 - super(message);
62.36 - }
62.37 -
62.38 - public FormatterException(Throwable cause) {
62.39 - super(cause);
62.40 - }
62.41 -
62.42 - public FormatterException(String message, Throwable cause) {
62.43 - super(message, cause);
62.44 - }
62.45 -}
63.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/SilentFormatter.java Mon Mar 04 17:06:42 2019 +0100
63.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
63.3 @@ -1,33 +0,0 @@
63.4 -/**
63.5 - * SQL-DK
63.6 - * Copyright © 2013 František Kučera (frantovo.cz)
63.7 - *
63.8 - * This program is free software: you can redistribute it and/or modify
63.9 - * it under the terms of the GNU General Public License as published by
63.10 - * the Free Software Foundation, either version 3 of the License, or
63.11 - * (at your option) any later version.
63.12 - *
63.13 - * This program is distributed in the hope that it will be useful,
63.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
63.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63.16 - * GNU General Public License for more details.
63.17 - *
63.18 - * You should have received a copy of the GNU General Public License
63.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
63.20 - */
63.21 -package info.globalcode.sql.dk.formatting;
63.22 -
63.23 -/**
63.24 - * Does not output anything, can be used instead of
63.25 - * <code>/dev/null</code>.
63.26 - *
63.27 - * @author Ing. František Kučera (frantovo.cz)
63.28 - */
63.29 -public class SilentFormatter extends AbstractFormatter {
63.30 -
63.31 - public static final String NAME = "silent"; // bash-completion:formatter
63.32 -
63.33 - public SilentFormatter(FormatterContext formatterContext) {
63.34 - super(formatterContext);
63.35 - }
63.36 -}
64.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/SingleRecordFormatter.java Mon Mar 04 17:06:42 2019 +0100
64.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
64.3 @@ -1,105 +0,0 @@
64.4 -/**
64.5 - * SQL-DK
64.6 - * Copyright © 2015 František Kučera (frantovo.cz)
64.7 - *
64.8 - * This program is free software: you can redistribute it and/or modify
64.9 - * it under the terms of the GNU General Public License as published by
64.10 - * the Free Software Foundation, either version 3 of the License, or
64.11 - * (at your option) any later version.
64.12 - *
64.13 - * This program is distributed in the hope that it will be useful,
64.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
64.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
64.16 - * GNU General Public License for more details.
64.17 - *
64.18 - * You should have received a copy of the GNU General Public License
64.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
64.20 - */
64.21 -package info.globalcode.sql.dk.formatting;
64.22 -
64.23 -import info.globalcode.sql.dk.ColorfulPrintWriter;
64.24 -import info.globalcode.sql.dk.Functions;
64.25 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
64.26 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
64.27 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
64.28 -
64.29 -/**
64.30 - * Formatter intended for printing one record (or few records) with many columns.
64.31 - * Prints each colum name and its value on separate line.
64.32 - *
64.33 - * @author Ing. František Kučera (frantovo.cz)
64.34 - */
64.35 -@PropertyDeclaration(name = COLORFUL, defaultValue = "true", type = Boolean.class, description = COLORFUL_DESCRIPTION)
64.36 -public class SingleRecordFormatter extends AbstractFormatter {
64.37 -
64.38 - public static final String NAME = "record"; // bash-completion:formatter
64.39 - private final ColorfulPrintWriter out;
64.40 - private boolean firstResult = true;
64.41 -
64.42 - public SingleRecordFormatter(FormatterContext formatterContext) {
64.43 - super(formatterContext);
64.44 - out = new ColorfulPrintWriter(formatterContext.getOutputStream());
64.45 - out.setColorful(formatterContext.getProperties().getBoolean(COLORFUL, true));
64.46 - }
64.47 -
64.48 - @Override
64.49 - public void writeStartResultSet(ColumnsHeader header) {
64.50 - super.writeStartResultSet(header);
64.51 - printResultSeparator();
64.52 - }
64.53 -
64.54 - @Override
64.55 - public void writeStartRow() {
64.56 - super.writeStartRow();
64.57 - printRecordSeparator();
64.58 - out.print(ColorfulPrintWriter.TerminalColor.Red, "Record: ");
64.59 - out.print(getCurrentRowCount());
64.60 - println();
64.61 - }
64.62 -
64.63 - @Override
64.64 - public void writeColumnValue(Object value) {
64.65 - super.writeColumnValue(value);
64.66 - String columnName = getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel();
64.67 - out.print(ColorfulPrintWriter.TerminalColor.Green, columnName + ": ");
64.68 - Functions.printValueWithWhitespaceReplaced(out, toString(value), null, ColorfulPrintWriter.TerminalColor.Red);
64.69 - println();
64.70 - }
64.71 -
64.72 - private static String toString(Object value) {
64.73 - return String.valueOf(value);
64.74 - }
64.75 -
64.76 - @Override
64.77 - public void writeUpdatesResult(int updatedRowsCount) {
64.78 - super.writeUpdatesResult(updatedRowsCount);
64.79 - printResultSeparator();
64.80 - out.print(ColorfulPrintWriter.TerminalColor.Red, "Updated records: ");
64.81 - out.println(updatedRowsCount);
64.82 - printBellAndFlush();
64.83 - }
64.84 -
64.85 - private void printBellAndFlush() {
64.86 - out.bell();
64.87 - out.flush();
64.88 - }
64.89 -
64.90 - private void println() {
64.91 - out.println();
64.92 - printBellAndFlush();
64.93 - }
64.94 -
64.95 - private void printRecordSeparator() {
64.96 - if (getCurrentRowCount() > 1) {
64.97 - println();
64.98 - }
64.99 - }
64.100 -
64.101 - private void printResultSeparator() {
64.102 - if (firstResult) {
64.103 - firstResult = false;
64.104 - } else {
64.105 - println();
64.106 - }
64.107 - }
64.108 -}
65.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/SingleValueFormatter.java Mon Mar 04 17:06:42 2019 +0100
65.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
65.3 @@ -1,52 +0,0 @@
65.4 -/**
65.5 - * SQL-DK
65.6 - * Copyright © 2013 František Kučera (frantovo.cz)
65.7 - *
65.8 - * This program is free software: you can redistribute it and/or modify
65.9 - * it under the terms of the GNU General Public License as published by
65.10 - * the Free Software Foundation, either version 3 of the License, or
65.11 - * (at your option) any later version.
65.12 - *
65.13 - * This program is distributed in the hope that it will be useful,
65.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
65.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
65.16 - * GNU General Public License for more details.
65.17 - *
65.18 - * You should have received a copy of the GNU General Public License
65.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
65.20 - */
65.21 -package info.globalcode.sql.dk.formatting;
65.22 -
65.23 -import java.io.PrintWriter;
65.24 -
65.25 -/**
65.26 - * Prints just the value without any formatting. If the result set contains multiple records or
65.27 - * columns, the values are simply concatenate without any separators. If updates result is returned,
65.28 - * the updated records count is printed.
65.29 - *
65.30 - * @author Ing. František Kučera (frantovo.cz)
65.31 - */
65.32 -public class SingleValueFormatter extends AbstractFormatter {
65.33 -
65.34 - public static final String NAME = "single"; // bash-completion:formatter
65.35 - private PrintWriter out;
65.36 -
65.37 - public SingleValueFormatter(FormatterContext formatterContext) {
65.38 - super(formatterContext);
65.39 - this.out = new PrintWriter(formatterContext.getOutputStream());
65.40 - }
65.41 -
65.42 - @Override
65.43 - public void writeColumnValue(Object value) {
65.44 - super.writeColumnValue(value);
65.45 - out.print(String.valueOf(value));
65.46 - out.flush();
65.47 - }
65.48 -
65.49 - @Override
65.50 - public void writeUpdatesResult(int updatedRowsCount) {
65.51 - super.writeUpdatesResult(updatedRowsCount);
65.52 - out.print(updatedRowsCount);
65.53 - out.flush();
65.54 - }
65.55 -}
66.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularFormatter.java Mon Mar 04 17:06:42 2019 +0100
66.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
66.3 @@ -1,308 +0,0 @@
66.4 -/**
66.5 - * SQL-DK
66.6 - * Copyright © 2013 František Kučera (frantovo.cz)
66.7 - *
66.8 - * This program is free software: you can redistribute it and/or modify
66.9 - * it under the terms of the GNU General Public License as published by
66.10 - * the Free Software Foundation, either version 3 of the License, or
66.11 - * (at your option) any later version.
66.12 - *
66.13 - * This program is distributed in the hope that it will be useful,
66.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
66.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66.16 - * GNU General Public License for more details.
66.17 - *
66.18 - * You should have received a copy of the GNU General Public License
66.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
66.20 - */
66.21 -package info.globalcode.sql.dk.formatting;
66.22 -
66.23 -import info.globalcode.sql.dk.ColorfulPrintWriter;
66.24 -import static info.globalcode.sql.dk.ColorfulPrintWriter.*;
66.25 -import info.globalcode.sql.dk.Functions;
66.26 -import static info.globalcode.sql.dk.Functions.lpad;
66.27 -import static info.globalcode.sql.dk.Functions.rpad;
66.28 -import static info.globalcode.sql.dk.Functions.repeat;
66.29 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
66.30 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
66.31 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
66.32 -import java.sql.SQLException;
66.33 -import java.sql.SQLXML;
66.34 -import java.util.List;
66.35 -import java.util.logging.Level;
66.36 -import java.util.logging.Logger;
66.37 -
66.38 -/**
66.39 - * <p>
66.40 - * Prints human-readable output – tables of result sets and text messages with update counts.
66.41 - * </p>
66.42 - *
66.43 - * <p>
66.44 - * Longer values might break the table – overflow the cells – see alternative tabular formatters and
66.45 - * the {@linkplain #PROPERTY_TRIM} property.
66.46 - * </p>
66.47 - *
66.48 - * @author Ing. František Kučera (frantovo.cz)
66.49 - * @see TabularPrefetchingFormatter
66.50 - * @see TabularWrappingFormatter
66.51 - */
66.52 -@PropertyDeclaration(name = COLORFUL, defaultValue = "true", type = Boolean.class, description = COLORFUL_DESCRIPTION)
66.53 -@PropertyDeclaration(name = TabularFormatter.PROPERTY_ASCII, defaultValue = "false", type = Boolean.class, description = "whether to use ASCII table borders instead of unicode ones")
66.54 -@PropertyDeclaration(name = TabularFormatter.PROPERTY_TRIM, defaultValue = "false", type = Boolean.class, description = "whether to trim the values to fit the column width")
66.55 -@PropertyDeclaration(name = TabularFormatter.PROPERTY_HEADER_TYPE, defaultValue = "true", type = Boolean.class, description = "whether to print data types in column headers")
66.56 -public class TabularFormatter extends AbstractFormatter {
66.57 -
66.58 - private static final Logger log = Logger.getLogger(TabularFormatter.class.getName());
66.59 - public static final String NAME = "tabular"; // bash-completion:formatter
66.60 - private static final String HEADER_TYPE_PREFIX = " (";
66.61 - private static final String HEADER_TYPE_SUFFIX = ")";
66.62 - public static final String PROPERTY_ASCII = "ascii";
66.63 - public static final String PROPERTY_TRIM = "trim";
66.64 - public static final String PROPERTY_HEADER_TYPE = "headerTypes";
66.65 - protected ColorfulPrintWriter out;
66.66 - private boolean firstResult = true;
66.67 - private int[] columnWidth;
66.68 - /**
66.69 - * use ASCII borders instead of unicode ones
66.70 - */
66.71 - private final boolean asciiNostalgia;
66.72 - /**
66.73 - * Trim values if they are longer than cell size
66.74 - */
66.75 - private final boolean trimValues;
66.76 - /**
66.77 - * Print data type of each column in the header
66.78 - */
66.79 - private final boolean printHeaderTypes;
66.80 -
66.81 - public TabularFormatter(FormatterContext formatterContext) {
66.82 - super(formatterContext);
66.83 - out = new ColorfulPrintWriter(formatterContext.getOutputStream());
66.84 - asciiNostalgia = formatterContext.getProperties().getBoolean(PROPERTY_ASCII, false);
66.85 - trimValues = formatterContext.getProperties().getBoolean(PROPERTY_TRIM, false);
66.86 - printHeaderTypes = formatterContext.getProperties().getBoolean(PROPERTY_HEADER_TYPE, true);
66.87 - out.setColorful(formatterContext.getProperties().getBoolean(COLORFUL, true));
66.88 - }
66.89 -
66.90 - @Override
66.91 - public void writeStartResultSet(ColumnsHeader header) {
66.92 - super.writeStartResultSet(header);
66.93 - printResultSeparator();
66.94 -
66.95 - initColumnWidths(header.getColumnCount());
66.96 -
66.97 - printTableIndent();
66.98 - printTableBorder("╭");
66.99 -
66.100 - List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
66.101 -
66.102 - for (ColumnDescriptor cd : columnDescriptors) {
66.103 - // padding: make header cell at least same width as data cells in this column
66.104 - int typeWidth = printHeaderTypes ? cd.getTypeName().length() + HEADER_TYPE_PREFIX.length() + HEADER_TYPE_SUFFIX.length() : 0;
66.105 - cd.setLabel(rpad(cd.getLabel(), getColumnWidth(cd.getColumnNumber()) - typeWidth));
66.106 - updateColumnWidth(cd.getColumnNumber(), cd.getLabel().length() + typeWidth);
66.107 -
66.108 - if (!cd.isFirstColumn()) {
66.109 - printTableBorder("┬");
66.110 - }
66.111 - printTableBorder(repeat('─', getColumnWidth(cd.getColumnNumber()) + 2));
66.112 - }
66.113 - printTableBorder("╮");
66.114 - out.println();
66.115 -
66.116 - for (ColumnDescriptor cd : columnDescriptors) {
66.117 - if (cd.isFirstColumn()) {
66.118 - printTableIndent();
66.119 - printTableBorder("│ ");
66.120 - } else {
66.121 - printTableBorder(" │ ");
66.122 - }
66.123 - out.print(TerminalStyle.Bright, cd.getLabel());
66.124 - if (printHeaderTypes) {
66.125 - out.print(HEADER_TYPE_PREFIX);
66.126 - out.print(cd.getTypeName());
66.127 - out.print(HEADER_TYPE_SUFFIX);
66.128 - }
66.129 - if (cd.isLastColumn()) {
66.130 - printTableBorder(" │");
66.131 - }
66.132 - }
66.133 - out.println();
66.134 -
66.135 - printTableIndent();
66.136 - printTableBorder("├");
66.137 - for (int i = 1; i <= header.getColumnCount(); i++) {
66.138 - if (i > 1) {
66.139 - printTableBorder("┼");
66.140 - }
66.141 - printTableBorder(repeat('─', getColumnWidth(i) + 2));
66.142 - }
66.143 - printTableBorder("┤");
66.144 - out.println();
66.145 -
66.146 - out.flush();
66.147 - }
66.148 -
66.149 - /**
66.150 - * Must be called before {@linkplain #updateColumnWidth(int, int)} and
66.151 - * {@linkplain #getColumnWidth(int)} for each result set.
66.152 - *
66.153 - * @param columnCount number of columns in current result set
66.154 - */
66.155 - protected void initColumnWidths(int columnCount) {
66.156 - if (columnWidth == null) {
66.157 - columnWidth = new int[columnCount];
66.158 - }
66.159 - }
66.160 -
66.161 - protected void cleanColumnWidths() {
66.162 - columnWidth = null;
66.163 - }
66.164 -
66.165 - @Override
66.166 - public void writeColumnValue(Object value) {
66.167 - super.writeColumnValue(value);
66.168 - writeColumnValueInternal(value);
66.169 - }
66.170 -
66.171 - protected void writeColumnValueInternal(Object value) {
66.172 -
66.173 - if (isCurrentColumnFirst()) {
66.174 - printTableIndent();
66.175 - printTableBorder("│ ");
66.176 - } else {
66.177 - printTableBorder(" │ ");
66.178 - }
66.179 -
66.180 - printValueWithWhitespaceReplaced(toString(value));
66.181 -
66.182 - if (isCurrentColumnLast()) {
66.183 - printTableBorder(" │");
66.184 - }
66.185 -
66.186 - }
66.187 -
66.188 - protected void printValueWithWhitespaceReplaced(String text) {
66.189 - Functions.printValueWithWhitespaceReplaced(out, text, TerminalColor.Cyan, TerminalColor.Red);
66.190 - }
66.191 -
66.192 - protected int getColumnWidth(int columnNumber) {
66.193 - return columnWidth[columnNumber - 1];
66.194 - }
66.195 -
66.196 - private void setColumnWidth(int columnNumber, int width) {
66.197 - columnWidth[columnNumber - 1] = width;
66.198 - }
66.199 -
66.200 - protected void updateColumnWidth(int columnNumber, int width) {
66.201 - int oldWidth = getColumnWidth(columnNumber);
66.202 - setColumnWidth(columnNumber, Math.max(width, oldWidth));
66.203 -
66.204 - }
66.205 -
66.206 - protected String toString(Object value) {
66.207 - final int width = getColumnWidth(getCurrentColumnsCount());
66.208 - String result;
66.209 - if (value instanceof Number || value instanceof Boolean) {
66.210 - result = lpad(String.valueOf(value), width);
66.211 - } else {
66.212 - if (value instanceof SQLXML) {
66.213 - // TODO: move to a common method, share with other formatters
66.214 - try {
66.215 - value = ((SQLXML) value).getString();
66.216 - } catch (SQLException e) {
66.217 - log.log(Level.SEVERE, "Unable to format XML", e);
66.218 - }
66.219 - }
66.220 -
66.221 - result = rpad(String.valueOf(value), width);
66.222 - }
66.223 - // ? value = (boolean) value ? "✔" : "✗";
66.224 -
66.225 - if (trimValues && result.length() > width) {
66.226 - result = result.substring(0, width - 1) + "…";
66.227 - }
66.228 -
66.229 - return result;
66.230 - }
66.231 -
66.232 - @Override
66.233 - public void writeEndRow() {
66.234 - super.writeEndRow();
66.235 - writeEndRowInternal();
66.236 - }
66.237 -
66.238 - public void writeEndRowInternal() {
66.239 - out.println();
66.240 - out.flush();
66.241 - }
66.242 -
66.243 - @Override
66.244 - public void writeEndResultSet() {
66.245 - int columnCount = getCurrentColumnsHeader().getColumnCount();
66.246 - super.writeEndResultSet();
66.247 -
66.248 - printTableIndent();
66.249 - printTableBorder("╰");
66.250 - for (int i = 1; i <= columnCount; i++) {
66.251 - if (i > 1) {
66.252 - printTableBorder("┴");
66.253 - }
66.254 - printTableBorder(repeat('─', getColumnWidth(i) + 2));
66.255 - }
66.256 - printTableBorder("╯");
66.257 - out.println();
66.258 -
66.259 - cleanColumnWidths();
66.260 -
66.261 - out.print(TerminalColor.Yellow, "Record count: ");
66.262 - out.println(getCurrentRowCount());
66.263 - out.bell();
66.264 - out.flush();
66.265 - }
66.266 -
66.267 - @Override
66.268 - public void writeUpdatesResult(int updatedRowsCount) {
66.269 - super.writeUpdatesResult(updatedRowsCount);
66.270 - printResultSeparator();
66.271 - out.print(TerminalColor.Red, "Updated records: ");
66.272 - out.println(updatedRowsCount);
66.273 - out.bell();
66.274 - out.flush();
66.275 - }
66.276 -
66.277 - @Override
66.278 - public void writeEndDatabase() {
66.279 - super.writeEndDatabase();
66.280 - out.flush();
66.281 - }
66.282 -
66.283 - private void printResultSeparator() {
66.284 - if (firstResult) {
66.285 - firstResult = false;
66.286 - } else {
66.287 - out.println();
66.288 - }
66.289 - }
66.290 -
66.291 - protected void printTableBorder(String border) {
66.292 - if (asciiNostalgia) {
66.293 - border = border.replaceAll("─", "-");
66.294 - border = border.replaceAll("│", "|");
66.295 - border = border.replaceAll("[╭┬╮├┼┤╰┴╯]", "+");
66.296 - }
66.297 -
66.298 - out.print(TerminalColor.Green, border);
66.299 - }
66.300 -
66.301 - protected void printTableIndent() {
66.302 - out.print(" ");
66.303 - }
66.304 -
66.305 - /**
66.306 - * @return whether should print only ASCII characters instead of unlimited Unicode.
66.307 - */
66.308 - protected boolean isAsciiNostalgia() {
66.309 - return asciiNostalgia;
66.310 - }
66.311 -}
67.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java Mon Mar 04 17:06:42 2019 +0100
67.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
67.3 @@ -1,119 +0,0 @@
67.4 -/**
67.5 - * SQL-DK
67.6 - * Copyright © 2013 František Kučera (frantovo.cz)
67.7 - *
67.8 - * This program is free software: you can redistribute it and/or modify
67.9 - * it under the terms of the GNU General Public License as published by
67.10 - * the Free Software Foundation, either version 3 of the License, or
67.11 - * (at your option) any later version.
67.12 - *
67.13 - * This program is distributed in the hope that it will be useful,
67.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
67.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67.16 - * GNU General Public License for more details.
67.17 - *
67.18 - * You should have received a copy of the GNU General Public License
67.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
67.20 - */
67.21 -package info.globalcode.sql.dk.formatting;
67.22 -
67.23 -import java.util.ArrayList;
67.24 -import java.util.List;
67.25 -
67.26 -/**
67.27 - * <p>
67.28 - * Prefetches whole result set and computes column widths. Whole table is flushed at once in
67.29 - * {@linkplain #writeEndResultSet()}.
67.30 - * </p>
67.31 - *
67.32 - * <p>
67.33 - * Long values will not overflow the cells, but whole result set must be loaded into the memory.
67.34 - * </p>
67.35 - *
67.36 - * @author Ing. František Kučera (frantovo.cz)
67.37 - */
67.38 -public class TabularPrefetchingFormatter extends TabularFormatter {
67.39 -
67.40 - public static final String NAME = "tabular-prefetching"; // bash-completion:formatter
67.41 - private ColumnsHeader currentHeader;
67.42 - private List<Object[]> currentResultSet;
67.43 - private Object[] currentRow;
67.44 - private int currentColumnsCount;
67.45 - private boolean prefetchDone = false;
67.46 -
67.47 - public TabularPrefetchingFormatter(FormatterContext formatterContext) {
67.48 - super(formatterContext);
67.49 - }
67.50 -
67.51 - @Override
67.52 - protected int getCurrentColumnsCount() {
67.53 - if (prefetchDone) {
67.54 - return super.getCurrentColumnsCount();
67.55 - } else {
67.56 - return currentColumnsCount;
67.57 - }
67.58 - }
67.59 -
67.60 - @Override
67.61 - public void writeStartResultSet(ColumnsHeader header) {
67.62 - currentResultSet = new ArrayList<>();
67.63 - currentHeader = header;
67.64 - initColumnWidths(header.getColumnCount());
67.65 - }
67.66 -
67.67 - @Override
67.68 - public void writeStartRow() {
67.69 - currentRow = new Object[currentHeader.getColumnCount()];
67.70 - currentResultSet.add(currentRow);
67.71 - currentColumnsCount = 0;
67.72 - }
67.73 -
67.74 - @Override
67.75 - public void writeColumnValue(Object value) {
67.76 - currentRow[currentColumnsCount] = value;
67.77 - currentColumnsCount++;
67.78 - String textRepresentation = toString(value);
67.79 - /** TODO: count only printable characters (currently not an issue) */
67.80 - updateColumnWidth(currentColumnsCount, textRepresentation.length());
67.81 - }
67.82 -
67.83 - @Override
67.84 - public void writeEndRow() {
67.85 - // do nothing
67.86 - }
67.87 -
67.88 - @Override
67.89 - public void writeEndResultSet() {
67.90 - prefetchDone = true;
67.91 -
67.92 - postprocessPrefetchedResultSet(currentHeader, currentResultSet);
67.93 -
67.94 - super.writeStartResultSet(currentHeader);
67.95 -
67.96 - for (Object[] row : currentResultSet) {
67.97 - super.writeStartRow();
67.98 - for (Object cell : row) {
67.99 - super.writeColumnValue(cell);
67.100 - }
67.101 - super.writeEndRow();
67.102 - }
67.103 -
67.104 - currentColumnsCount = 0;
67.105 - currentHeader = null;
67.106 - currentRow = null;
67.107 - currentResultSet = null;
67.108 - super.writeEndResultSet();
67.109 - prefetchDone = false;
67.110 - }
67.111 -
67.112 - /**
67.113 - * Optional post-processing – override in sub-classes if needed.
67.114 - * Don't forget to {@linkplain #updateColumnWidth(int, int)}
67.115 - *
67.116 - * @param currentHeader
67.117 - * @param currentResultSet
67.118 - */
67.119 - protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
67.120 - }
67.121 -
67.122 -}
68.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TabularWrappingFormatter.java Mon Mar 04 17:06:42 2019 +0100
68.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
68.3 @@ -1,116 +0,0 @@
68.4 -/**
68.5 - * SQL-DK
68.6 - * Copyright © 2014 František Kučera (frantovo.cz)
68.7 - *
68.8 - * This program is free software: you can redistribute it and/or modify
68.9 - * it under the terms of the GNU General Public License as published by
68.10 - * the Free Software Foundation, either version 3 of the License, or
68.11 - * (at your option) any later version.
68.12 - *
68.13 - * This program is distributed in the hope that it will be useful,
68.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
68.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
68.16 - * GNU General Public License for more details.
68.17 - *
68.18 - * You should have received a copy of the GNU General Public License
68.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
68.20 - */
68.21 -package info.globalcode.sql.dk.formatting;
68.22 -
68.23 -import info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
68.24 -import java.util.ArrayList;
68.25 -import java.util.List;
68.26 -import static info.globalcode.sql.dk.Functions.lpad;
68.27 -import static info.globalcode.sql.dk.Functions.rpad;
68.28 -import static info.globalcode.sql.dk.Functions.repeat;
68.29 -
68.30 -/**
68.31 - * Longer values are line-wrapped – the cell then contains multiple lines. Marks are added to
68.32 - * signalize forced line ends (not present in original data).
68.33 - *
68.34 - * @author Ing. František Kučera (frantovo.cz)
68.35 - */
68.36 -public class TabularWrappingFormatter extends TabularFormatter {
68.37 -
68.38 - public static final String NAME = "tabular-wrapping"; // bash-completion:formatter
68.39 - private List<String[]> currentRow;
68.40 -
68.41 - public TabularWrappingFormatter(FormatterContext formatterContext) {
68.42 - super(formatterContext);
68.43 - }
68.44 -
68.45 - @Override
68.46 - public void writeStartResultSet(ColumnsHeader header) {
68.47 - super.writeStartResultSet(header);
68.48 - currentRow = new ArrayList<>(header.getColumnCount());
68.49 - }
68.50 -
68.51 - @Override
68.52 - protected void writeColumnValueInternal(Object value) {
68.53 - boolean rightAlign = value instanceof Number || value instanceof Boolean;
68.54 - String valueString = String.valueOf(value);
68.55 - int columnWidth = getColumnWidth(getCurrentColumnsCount()) - 1; // -1 = space for new line symbol
68.56 - currentRow.add(wrapLines(valueString, columnWidth, rightAlign));
68.57 - }
68.58 -
68.59 - @Override
68.60 - public void writeEndRow() {
68.61 - super.writeEndRow();
68.62 -
68.63 - int wrappedLine = 0;
68.64 - boolean hasMoreWrappedLines;
68.65 -
68.66 - do {
68.67 - hasMoreWrappedLines = false;
68.68 - for (int i = 0; i < currentRow.size(); i++) {
68.69 - if (i == 0) {
68.70 - printTableIndent();
68.71 - printTableBorder("│ ");
68.72 - } else {
68.73 - printTableBorder(" │ ");
68.74 - }
68.75 - String[] columnArray = currentRow.get(i);
68.76 - if (wrappedLine < columnArray.length) {
68.77 - printValueWithWhitespaceReplaced(columnArray[wrappedLine]);
68.78 -
68.79 - if (wrappedLine < columnArray.length - 1) {
68.80 - out.print(TerminalColor.Red, "↩");
68.81 - hasMoreWrappedLines = true;
68.82 - } else {
68.83 - out.print(" ");
68.84 - }
68.85 -
68.86 - } else {
68.87 - out.print(repeat(' ', getColumnWidth(i + 1)));
68.88 - }
68.89 -
68.90 - if (i == (currentRow.size() - 1)) {
68.91 - printTableBorder(" │");
68.92 - }
68.93 - }
68.94 - out.println();
68.95 - out.flush();
68.96 - wrappedLine++;
68.97 - } while (hasMoreWrappedLines);
68.98 -
68.99 - currentRow.clear();
68.100 - }
68.101 -
68.102 - @Override
68.103 - public void writeEndRowInternal() {
68.104 - // already done – wrapped row ends
68.105 - }
68.106 -
68.107 - private static String[] wrapLines(String s, int width, boolean rightAlign) {
68.108 - String[] array = new String[(s.length() - 1) / width + 1];
68.109 - for (int i = 0; i < array.length; i++) {
68.110 - if (i == array.length - 1) {
68.111 - String part = s.substring(i * width, s.length());
68.112 - array[i] = rightAlign ? lpad(part, width) : rpad(part, width);
68.113 - } else {
68.114 - array[i] = s.substring(i * width, (i + 1) * width);
68.115 - }
68.116 - }
68.117 - return array;
68.118 - }
68.119 -}
69.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/TeXFormatter.java Mon Mar 04 17:06:42 2019 +0100
69.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
69.3 @@ -1,208 +0,0 @@
69.4 -/**
69.5 - * SQL-DK
69.6 - * Copyright © 2014 František Kučera (frantovo.cz)
69.7 - *
69.8 - * This program is free software: you can redistribute it and/or modify
69.9 - * it under the terms of the GNU General Public License as published by
69.10 - * the Free Software Foundation, either version 3 of the License, or
69.11 - * (at your option) any later version.
69.12 - *
69.13 - * This program is distributed in the hope that it will be useful,
69.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
69.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69.16 - * GNU General Public License for more details.
69.17 - *
69.18 - * You should have received a copy of the GNU General Public License
69.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
69.20 - */
69.21 -package info.globalcode.sql.dk.formatting;
69.22 -
69.23 -import info.globalcode.sql.dk.ColorfulPrintWriter;
69.24 -import info.globalcode.sql.dk.Constants;
69.25 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
69.26 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
69.27 -import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
69.28 -import java.util.Collections;
69.29 -import java.util.HashMap;
69.30 -import java.util.List;
69.31 -import java.util.Map;
69.32 -
69.33 -/**
69.34 - * Outputs result sets in (La)TeX format.
69.35 - *
69.36 - * @author Ing. František Kučera (frantovo.cz)
69.37 - */
69.38 -@PropertyDeclaration(name = COLORFUL, defaultValue = "false", type = Boolean.class, description = COLORFUL_DESCRIPTION)
69.39 -public class TeXFormatter extends AbstractFormatter {
69.40 -
69.41 - public static final String NAME = "tex"; // bash-completion:formatter
69.42 - private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
69.43 - private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
69.44 - private static final Map<Character, String> TEX_ESCAPE_MAP;
69.45 - private final ColorfulPrintWriter out;
69.46 -
69.47 - static {
69.48 - Map<Character, String> replacements = new HashMap<>();
69.49 -
69.50 - replacements.put('\\', "\\textbackslash{}");
69.51 - replacements.put('{', "\\{{}");
69.52 - replacements.put('}', "\\}{}");
69.53 - replacements.put('_', "\\_{}");
69.54 - replacements.put('^', "\\textasciicircum{}");
69.55 - replacements.put('#', "\\#{}");
69.56 - replacements.put('&', "\\&{}");
69.57 - replacements.put('$', "\\${}");
69.58 - replacements.put('%', "\\%{}");
69.59 - replacements.put('~', "\\textasciitilde{}");
69.60 - replacements.put('-', "{-}");
69.61 -
69.62 - TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
69.63 - }
69.64 -
69.65 - public TeXFormatter(FormatterContext formatterContext) {
69.66 - super(formatterContext);
69.67 - boolean colorful = formatterContext.getProperties().getBoolean(COLORFUL, false);
69.68 - out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
69.69 - }
69.70 -
69.71 - @Override
69.72 - public void writeStartBatch() {
69.73 - super.writeStartBatch();
69.74 -
69.75 - printCommand("documentclass", "a4paper,twoside", "article", true);
69.76 - printCommand("usepackage", "T1", "fontenc", true);
69.77 - printCommand("usepackage", "utf8x", "inputenc", true);
69.78 - printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
69.79 - printBegin("document");
69.80 - }
69.81 -
69.82 - @Override
69.83 - public void writeEndBatch() {
69.84 - super.writeEndBatch();
69.85 - printEnd("document");
69.86 - }
69.87 -
69.88 - @Override
69.89 - public void writeColumnValue(Object value) {
69.90 - super.writeColumnValue(value);
69.91 - // TODO: arrays, numbers, booleans, nulls etc.:
69.92 - out.print(escapeTex(toString(value)));
69.93 -
69.94 - if (!isCurrentColumnLast()) {
69.95 - printColumnSeparator();
69.96 - }
69.97 - }
69.98 -
69.99 - @Override
69.100 - public void writeEndRow() {
69.101 - super.writeEndRow();
69.102 - printEndRow();
69.103 - }
69.104 -
69.105 - @Override
69.106 - public void writeStartResultSet(ColumnsHeader header) {
69.107 - super.writeStartResultSet(header);
69.108 - printCommand("begin", null, "tabular", false);
69.109 -
69.110 - List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
69.111 -
69.112 - StringBuilder columnAlignments = new StringBuilder();
69.113 - for (ColumnDescriptor cd : columnDescriptors) {
69.114 - if (cd.isNumeric() || cd.isBoolean()) {
69.115 - columnAlignments.append('r');
69.116 - } else {
69.117 - columnAlignments.append('l');
69.118 - }
69.119 - }
69.120 -
69.121 - printCommand(null, null, columnAlignments.toString(), true);
69.122 - printCommand("hline", null, null, true);
69.123 -
69.124 - for (ColumnDescriptor cd : columnDescriptors) {
69.125 - printCommand("textbf", null, cd.getLabel(), false);
69.126 - if (cd.isLastColumn()) {
69.127 - printEndRow();
69.128 - } else {
69.129 - printColumnSeparator();
69.130 - }
69.131 - }
69.132 -
69.133 - printCommand("hline", null, null, true);
69.134 - }
69.135 -
69.136 - @Override
69.137 - public void writeEndResultSet() {
69.138 - super.writeEndResultSet();
69.139 - printCommand("hline", null, null, true);
69.140 - printEnd("tabular");
69.141 - }
69.142 -
69.143 - private String escapeTex(String text) {
69.144 - if (text == null) {
69.145 - return null;
69.146 - } else {
69.147 - StringBuilder result = new StringBuilder(text.length() * 2);
69.148 -
69.149 - for (char ch : text.toCharArray()) {
69.150 - String replacement = TEX_ESCAPE_MAP.get(ch);
69.151 - result.append(replacement == null ? ch : replacement);
69.152 - }
69.153 -
69.154 - return result.toString();
69.155 - }
69.156 - }
69.157 -
69.158 - protected String toString(Object value) {
69.159 - return String.valueOf(value);
69.160 - }
69.161 -
69.162 - private void printColumnSeparator() {
69.163 - out.print(COMMAND_COLOR, " & ");
69.164 - }
69.165 -
69.166 - private void printEndRow() {
69.167 - out.println(COMMAND_COLOR, " \\\\");
69.168 - out.flush();
69.169 - }
69.170 -
69.171 - /**
69.172 - *
69.173 - * @param command will not be escaped – should contain just a valid TeX command name
69.174 - * @param options will not be escaped – should be properly formatted to be printed inside [
69.175 - * and ]
69.176 - * @param value will be escaped
69.177 - * @param println whether to print line end and flush
69.178 - */
69.179 - private void printCommand(String command, String options, String value, boolean println) {
69.180 -
69.181 - if (command != null) {
69.182 - out.print(COMMAND_COLOR, "\\" + command);
69.183 - }
69.184 -
69.185 - if (options != null) {
69.186 - out.print(COMMAND_COLOR, "[");
69.187 - out.print(OPTIONS_COLOR, options);
69.188 - out.print(COMMAND_COLOR, "]");
69.189 - }
69.190 -
69.191 - if (value != null) {
69.192 - out.print(COMMAND_COLOR, "{");
69.193 - out.print(escapeTex(value));
69.194 - out.print(COMMAND_COLOR, "}");
69.195 - }
69.196 -
69.197 - if (println) {
69.198 - out.println();
69.199 - out.flush();
69.200 - }
69.201 - }
69.202 -
69.203 - private void printBegin(String environment) {
69.204 - printCommand("begin", null, environment, true);
69.205 - }
69.206 -
69.207 - private void printEnd(String environment) {
69.208 - printCommand("end", null, environment, true);
69.209 - }
69.210 -
69.211 -}
70.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/XhtmlFormatter.java Mon Mar 04 17:06:42 2019 +0100
70.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
70.3 @@ -1,262 +0,0 @@
70.4 -/**
70.5 - * SQL-DK
70.6 - * Copyright © 2014 František Kučera (frantovo.cz)
70.7 - *
70.8 - * This program is free software: you can redistribute it and/or modify
70.9 - * it under the terms of the GNU General Public License as published by
70.10 - * the Free Software Foundation, either version 3 of the License, or
70.11 - * (at your option) any later version.
70.12 - *
70.13 - * This program is distributed in the hope that it will be useful,
70.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
70.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
70.16 - * GNU General Public License for more details.
70.17 - *
70.18 - * You should have received a copy of the GNU General Public License
70.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
70.20 - */
70.21 -package info.globalcode.sql.dk.formatting;
70.22 -
70.23 -import info.globalcode.sql.dk.Constants;
70.24 -import info.globalcode.sql.dk.NamedParameter;
70.25 -import info.globalcode.sql.dk.Parameter;
70.26 -import info.globalcode.sql.dk.Xmlns;
70.27 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
70.28 -import info.globalcode.sql.dk.configuration.Properties;
70.29 -import info.globalcode.sql.dk.configuration.Property;
70.30 -import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
70.31 -import java.sql.Array;
70.32 -import java.sql.SQLException;
70.33 -import java.util.Date;
70.34 -import java.util.List;
70.35 -import java.util.Map;
70.36 -import java.util.Scanner;
70.37 -import java.util.logging.Level;
70.38 -import java.util.logging.Logger;
70.39 -import javax.xml.namespace.QName;
70.40 -
70.41 -/**
70.42 - * Prints result sets and parameters as tables, SQL as preformatted and updates counts as
70.43 - * paragraphs. You can pick XHTML fragments (usually tabular data) and use it on your website or use
70.44 - * whole output as preview or report.
70.45 - *
70.46 - * @author Ing. František Kučera (frantovo.cz)
70.47 - */
70.48 -public class XhtmlFormatter extends AbstractXmlFormatter {
70.49 -
70.50 - private static final Logger log = Logger.getLogger(XhtmlFormatter.class.getName());
70.51 - public static final String NAME = "xhtml"; // bash-completion:formatter
70.52 - private static final String DOCTYPE = "html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN\" \"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd\"";
70.53 - private static final String CSS_FILE = "info/globalcode/sql/dk/formatter/XhtmlFormatter.css";
70.54 - private int statementCounter = 0;
70.55 - private int resultSetCounter = 0;
70.56 - private int updatesResultCounter = 0;
70.57 -
70.58 - public XhtmlFormatter(FormatterContext formatterContext) {
70.59 - super(addDefaults(formatterContext));
70.60 - }
70.61 -
70.62 - /**
70.63 - * Do not indent text – preserve whitespace for pre elements
70.64 - */
70.65 - private static FormatterContext addDefaults(FormatterContext formatterContext) {
70.66 - Properties defaults = new Properties(1);
70.67 - defaults.add(new Property(PROPERTY_INDENT_TEXT, "false"));
70.68 - formatterContext.getProperties().setLastDefaults(defaults);
70.69 - return formatterContext;
70.70 - }
70.71 -
70.72 - @Override
70.73 - public void writeStartBatch() {
70.74 - super.writeStartBatch();
70.75 - printStartDocument();
70.76 - printDoctype(DOCTYPE);
70.77 - printStartElement(qname("html"), singleAttribute(qname("xmlns"), Xmlns.XHTML));
70.78 -
70.79 - printStartElement(qname("head"));
70.80 - printTextElement(qname("title"), null, Constants.PROGRAM_NAME + ": batch results");
70.81 - printCss();
70.82 - printEndElement();
70.83 -
70.84 - printStartElement(qname("body"));
70.85 - }
70.86 -
70.87 - private void printCss() {
70.88 -
70.89 - try (Scanner css = new Scanner(getClass().getClassLoader().getResourceAsStream(CSS_FILE))) {
70.90 - printStartElement(qname("style"), singleAttribute(qname("type"), "text/css"));
70.91 - while (css.hasNext()) {
70.92 - printText(css.nextLine(), true);
70.93 - }
70.94 - printEndElement();
70.95 - }
70.96 - }
70.97 -
70.98 - @Override
70.99 - public void writeEndBatch() {
70.100 - super.writeEndBatch();
70.101 - printEndElement();
70.102 - printEndElement();
70.103 - printEndDocument();
70.104 - }
70.105 -
70.106 - @Override
70.107 - public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
70.108 - super.writeStartDatabase(databaseDefinition);
70.109 - printTextElement(qname("h1"), null, "Database: " + databaseDefinition.getName());
70.110 -
70.111 - printStartElement(qname("p"));
70.112 - printText("This is XHTML output of batch executed at: ", true);
70.113 - printText(new Date().toString(), true);
70.114 - printEndElement();
70.115 - }
70.116 -
70.117 - @Override
70.118 - public void writeQuery(String sql) {
70.119 - super.writeQuery(sql);
70.120 - printTextElement(qname("pre"), null, sql);
70.121 - }
70.122 -
70.123 - @Override
70.124 - public void writeParameters(List<? extends Parameter> parameters) {
70.125 - super.writeParameters(parameters);
70.126 -
70.127 - if (parameters == null || parameters.isEmpty()) {
70.128 - printTextElement(qname("p"), null, "(this query has no parameters)");
70.129 - } else {
70.130 - printTextElement(qname("h3"), null, "Parameters:");
70.131 -
70.132 - printStartElement(qname("table"));
70.133 -
70.134 - printStartElement(qname("thead"));
70.135 - printStartElement(qname("tr"));
70.136 - printTextElement(qname("td"), null, "id");
70.137 - printTextElement(qname("td"), null, "type");
70.138 - printTextElement(qname("td"), null, "value");
70.139 - printEndElement();
70.140 - printEndElement();
70.141 -
70.142 - printStartElement(qname("tbody"));
70.143 - for (int i = 0; i < parameters.size(); i++) {
70.144 - Parameter p = parameters.get(i);
70.145 - printStartElement(qname("tr"));
70.146 - String numberOrName;
70.147 - if (p instanceof NamedParameter) {
70.148 - numberOrName = ((NamedParameter) p).getName();
70.149 - } else {
70.150 - numberOrName = String.valueOf(i + 1);
70.151 - }
70.152 - printTextElement(qname("td"), null, numberOrName);
70.153 - printTextElement(qname("td"), null, p.getType().name());
70.154 - printTableData(p.getValue());
70.155 - printEndElement();
70.156 - }
70.157 - printEndElement();
70.158 -
70.159 - printEndElement();
70.160 - }
70.161 - }
70.162 -
70.163 - private void printTableData(Object value) {
70.164 -
70.165 - if (value instanceof Array) {
70.166 - Array sqlArray = (Array) value;
70.167 - try {
70.168 - Object[] array = (Object[]) sqlArray.getArray();
70.169 - printStartElement(qname("td"));
70.170 - printArray(array);
70.171 - printEndElement();
70.172 - } catch (SQLException e) {
70.173 - log.log(Level.SEVERE, "Unable to format array", e);
70.174 - printTableData(String.valueOf(value));
70.175 - }
70.176 - } else {
70.177 - Map<QName, String> attributes = null;
70.178 - if (value instanceof Number) {
70.179 - attributes = singleAttribute(qname("class"), "number");
70.180 - } else if (value instanceof Boolean) {
70.181 - attributes = singleAttribute(qname("class"), "boolean");
70.182 - }
70.183 - printTextElement(qname("td"), attributes, String.valueOf(value));
70.184 - }
70.185 - }
70.186 -
70.187 - private void printArray(Object[] array) {
70.188 - printStartElement(qname("ul"));
70.189 - for (Object o : array) {
70.190 - if (o instanceof Object[]) {
70.191 - printStartElement(qname("li"));
70.192 - printTextElement(qname("p"), null, "nested array:");
70.193 - printArray((Object[]) o);
70.194 - printEndElement();
70.195 - } else {
70.196 - printTextElement(qname("li"), null, String.valueOf(o));
70.197 - }
70.198 - }
70.199 - printEndElement();
70.200 - }
70.201 -
70.202 - @Override
70.203 - public void writeStartResultSet(ColumnsHeader header) {
70.204 - super.writeStartResultSet(header);
70.205 - resultSetCounter++;
70.206 - printEmptyElement(qname("hr"), null);
70.207 - printTextElement(qname("h3"), null, "Result set #" + resultSetCounter);
70.208 - printStartElement(qname("table"));
70.209 - printStartElement(qname("thead"));
70.210 - printStartElement(qname("tr"));
70.211 - for (ColumnDescriptor cd : header.getColumnDescriptors()) {
70.212 - // TODO: type
70.213 - printTextElement(qname("td"), null, cd.getLabel());
70.214 - }
70.215 - printEndElement();
70.216 - printEndElement();
70.217 -
70.218 - printStartElement(qname("tbody"));
70.219 - }
70.220 -
70.221 - @Override
70.222 - public void writeEndResultSet() {
70.223 - super.writeEndResultSet();
70.224 - printEndElement();
70.225 - printEndElement();
70.226 - printTextElement(qname("p"), null, "Record count: " + getCurrentRowCount());
70.227 - }
70.228 -
70.229 - @Override
70.230 - public void writeStartRow() {
70.231 - super.writeStartRow();
70.232 - printStartElement(qname("tr"));
70.233 - }
70.234 -
70.235 - @Override
70.236 - public void writeColumnValue(Object value) {
70.237 - super.writeColumnValue(value);
70.238 - printTableData(value);
70.239 - }
70.240 -
70.241 - @Override
70.242 - public void writeEndRow() {
70.243 - super.writeEndRow();
70.244 - printEndElement();
70.245 - }
70.246 -
70.247 - @Override
70.248 - public void writeStartStatement() {
70.249 - super.writeStartStatement();
70.250 - statementCounter++;
70.251 - printEmptyElement(qname("hr"), null);
70.252 - printTextElement(qname("h2"), null, "SQL statement #" + statementCounter);
70.253 - resultSetCounter = 0;
70.254 - updatesResultCounter = 0;
70.255 - }
70.256 -
70.257 - @Override
70.258 - public void writeUpdatesResult(int updatedRowsCount) {
70.259 - super.writeUpdatesResult(updatedRowsCount);
70.260 - updatesResultCounter++;
70.261 - printEmptyElement(qname("hr"), null);
70.262 - printTextElement(qname("h3"), null, "Updates result #" + updatesResultCounter);
70.263 - printTextElement(qname("p"), null, "Updated rows: " + updatedRowsCount);
70.264 - }
70.265 -}
71.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/formatting/XmlFormatter.java Mon Mar 04 17:06:42 2019 +0100
71.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
71.3 @@ -1,245 +0,0 @@
71.4 -/**
71.5 - * SQL-DK
71.6 - * Copyright © 2013 František Kučera (frantovo.cz)
71.7 - *
71.8 - * This program is free software: you can redistribute it and/or modify
71.9 - * it under the terms of the GNU General Public License as published by
71.10 - * the Free Software Foundation, either version 3 of the License, or
71.11 - * (at your option) any later version.
71.12 - *
71.13 - * This program is distributed in the hope that it will be useful,
71.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
71.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71.16 - * GNU General Public License for more details.
71.17 - *
71.18 - * You should have received a copy of the GNU General Public License
71.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
71.20 - */
71.21 -package info.globalcode.sql.dk.formatting;
71.22 -
71.23 -import info.globalcode.sql.dk.Parameter;
71.24 -import info.globalcode.sql.dk.Xmlns;
71.25 -import info.globalcode.sql.dk.configuration.DatabaseDefinition;
71.26 -import static info.globalcode.sql.dk.Functions.notNull;
71.27 -import info.globalcode.sql.dk.NamedParameter;
71.28 -import info.globalcode.sql.dk.configuration.PropertyDeclaration;
71.29 -import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
71.30 -import java.sql.Array;
71.31 -import java.sql.ResultSet;
71.32 -import java.sql.SQLException;
71.33 -import java.sql.SQLXML;
71.34 -import java.util.ArrayList;
71.35 -import java.util.LinkedHashMap;
71.36 -import java.util.List;
71.37 -import java.util.Map;
71.38 -import java.util.logging.Level;
71.39 -import java.util.logging.Logger;
71.40 -import javax.xml.namespace.QName;
71.41 -
71.42 -/**
71.43 - * <p>
71.44 - * Prints machine-readable output – XML document containing resultsets and updates count. Good
71.45 - * choice for further processing – e.g. XSL transformation.</p>
71.46 - *
71.47 - * <p>
71.48 - * TODO: XSD</p>
71.49 - *
71.50 - * @author Ing. František Kučera (frantovo.cz)
71.51 - */
71.52 -@PropertyDeclaration(name = XmlFormatter.PROPERTY_LABELED_COLUMNS, defaultValue = "false", type = Boolean.class, description = "whether to add 'label' attribute to each 'column' element")
71.53 -public class XmlFormatter extends AbstractXmlFormatter {
71.54 -
71.55 - public static final String NAME = "xml"; // bash-completion:formatter
71.56 - public static final String PROPERTY_LABELED_COLUMNS = "labeledColumns";
71.57 - private static final Logger log = Logger.getLogger(XmlFormatter.class.getName());
71.58 - private final boolean labeledColumns;
71.59 -
71.60 - public XmlFormatter(FormatterContext formatterContext) {
71.61 - super(formatterContext);
71.62 - labeledColumns = formatterContext.getProperties().getBoolean(PROPERTY_LABELED_COLUMNS, false);
71.63 - }
71.64 -
71.65 - @Override
71.66 - public void writeStartBatch() {
71.67 - super.writeStartBatch();
71.68 - printStartDocument();
71.69 - printStartElement(qname("batchResult"), singleAttribute(qname("xmlns"), Xmlns.BATCH_RESULT));
71.70 - }
71.71 -
71.72 - @Override
71.73 - public void writeEndBatch() {
71.74 - super.writeEndBatch();
71.75 - printEndElement();
71.76 - printEndDocument();
71.77 - }
71.78 -
71.79 - @Override
71.80 - public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
71.81 - super.writeStartDatabase(databaseDefinition);
71.82 - Map<QName, String> attributes = databaseDefinition.getName() == null ? null : singleAttribute(qname("name"), databaseDefinition.getName());
71.83 - printStartElement(qname("database"), attributes);
71.84 - }
71.85 -
71.86 - @Override
71.87 - public void writeEndDatabase() {
71.88 - super.writeEndDatabase();
71.89 - printEndElement();
71.90 - }
71.91 -
71.92 - @Override
71.93 - public void writeStartStatement() {
71.94 - super.writeStartStatement();
71.95 - printStartElement(qname("statement"));
71.96 - }
71.97 -
71.98 - @Override
71.99 - public void writeEndStatement() {
71.100 - super.writeEndStatement();
71.101 - printEndElement();
71.102 - }
71.103 -
71.104 - @Override
71.105 - public void writeQuery(String sql) {
71.106 - super.writeQuery(sql);
71.107 - printTextElement(qname("sql"), null, sql);
71.108 - }
71.109 -
71.110 - @Override
71.111 - public void writeParameters(List<? extends Parameter> parameters) {
71.112 - super.writeParameters(parameters);
71.113 -
71.114 - for (Parameter p : notNull(parameters)) {
71.115 -
71.116 - Map<QName, String> attributes = new LinkedHashMap<>(2);
71.117 - if (p instanceof NamedParameter) {
71.118 - attributes.put(qname("name"), ((NamedParameter) p).getName());
71.119 - }
71.120 - attributes.put(qname("type"), p.getType().name());
71.121 -
71.122 - printTextElement(qname("parameter"), attributes, String.valueOf(p.getValue()));
71.123 - }
71.124 -
71.125 - }
71.126 -
71.127 - @Override
71.128 - public void writeStartResultSet(ColumnsHeader header) {
71.129 - super.writeStartResultSet(header);
71.130 - printStartElement(qname("resultSet"));
71.131 -
71.132 - for (ColumnDescriptor cd : header.getColumnDescriptors()) {
71.133 - Map<QName, String> attributes = new LinkedHashMap<>(4);
71.134 - attributes.put(qname("label"), cd.getLabel());
71.135 - attributes.put(qname("name"), cd.getName());
71.136 - attributes.put(qname("typeName"), cd.getTypeName());
71.137 - attributes.put(qname("type"), String.valueOf(cd.getType()));
71.138 - printEmptyElement(qname("columnHeader"), attributes);
71.139 - }
71.140 - }
71.141 -
71.142 - @Override
71.143 - public void writeEndResultSet() {
71.144 - super.writeEndResultSet();
71.145 - printEndElement();
71.146 - }
71.147 -
71.148 - @Override
71.149 - public void writeStartRow() {
71.150 - super.writeStartRow();
71.151 - printStartElement(qname("row"));
71.152 - }
71.153 -
71.154 - @Override
71.155 - public void writeColumnValue(Object value) {
71.156 - super.writeColumnValue(value);
71.157 -
71.158 - Map<QName, String> attributes = null;
71.159 - if (labeledColumns) {
71.160 - attributes = new LinkedHashMap<>(2);
71.161 - attributes.put(qname("label"), getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel());
71.162 - }
71.163 -
71.164 - if (value == null) {
71.165 - if (attributes == null) {
71.166 - attributes = new LinkedHashMap<>(2);
71.167 - }
71.168 - attributes.put(qname("null"), "true");
71.169 - printEmptyElement(qname("column"), attributes);
71.170 - } else if (value instanceof Array) {
71.171 -
71.172 - Array sqlArray = (Array) value;
71.173 - try {
71.174 - Object[] array = (Object[]) sqlArray.getArray();
71.175 - printStartElement(qname("column"), attributes);
71.176 - printArray(array);
71.177 - printEndElement();
71.178 - } catch (SQLException e) {
71.179 - // FIXME: rewrite array formatting, remember array mode, don't try sqlArray.getArray() again and again if it has failed
71.180 - log.log(Level.SEVERE, "Unable to format array", e);
71.181 - try {
71.182 - ResultSet arrayResultSet = sqlArray.getResultSet();
71.183 - //int columnCount = arrayResultSet.getMetaData().getColumnCount();
71.184 - ArrayList<Object> arrayList = new ArrayList<>();
71.185 - while (arrayResultSet.next()) {
71.186 - arrayList.add(arrayResultSet.getObject(2));
71.187 - // for (int i = 1; i <= columnCount; i++) {
71.188 - // log.log(Level.INFO, "Array column {0} = {1}", new Object[]{i, arrayResultSet.getObject(i)});
71.189 - // }
71.190 - }
71.191 -
71.192 - printStartElement(qname("column"), attributes);
71.193 - // FIXME: instanceof SQLXML, see below
71.194 - printArray(arrayList.toArray());
71.195 - printEndElement();
71.196 -
71.197 - } catch (SQLException e2) {
71.198 - // FIXME: fix logging, error recovery
71.199 - log.log(Level.SEVERE, "Second level fuck up !!!", e2);
71.200 - }
71.201 -
71.202 - writeColumnValue(String.valueOf(value));
71.203 - }
71.204 -
71.205 - } else if (value instanceof SQLXML) { // FIXME: move to separate method, to AbstractFormatter?
71.206 - SQLXML xml = (SQLXML) value;
71.207 - // TODO: parse DOM/SAX and transplant XML, don't escape (optional)
71.208 - try {
71.209 - printTextElement(qname("column"), attributes, xml.getString());
71.210 - } catch (SQLException e) {
71.211 - log.log(Level.SEVERE, "Unable to format XML", e);
71.212 - writeColumnValue(String.valueOf(value));
71.213 - }
71.214 - } else {
71.215 - printTextElement(qname("column"), attributes, toString(value));
71.216 - }
71.217 - }
71.218 -
71.219 - private void printArray(Object[] array) {
71.220 - printStartElement(qname("array"));
71.221 - for (Object o : array) {
71.222 - if (o instanceof Object[]) {
71.223 - printStartElement(qname("item"));
71.224 - printArray((Object[]) o);
71.225 - printEndElement();
71.226 - } else {
71.227 - printTextElement(qname("item"), null, String.valueOf(o));
71.228 - }
71.229 - }
71.230 - printEndElement();
71.231 - }
71.232 -
71.233 - @Override
71.234 - public void writeEndRow() {
71.235 - super.writeEndRow();
71.236 - printEndElement();
71.237 - }
71.238 -
71.239 - @Override
71.240 - public void writeUpdatesResult(int updatedRowsCount) {
71.241 - super.writeUpdatesResult(updatedRowsCount);
71.242 - printTextElement(qname("updatedRows"), null, String.valueOf(updatedRowsCount));
71.243 - }
71.244 -
71.245 - protected String toString(Object value) {
71.246 - return String.valueOf(value);
71.247 - }
71.248 -}
72.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/jmx/ConnectionManagement.java Mon Mar 04 17:06:42 2019 +0100
72.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
72.3 @@ -1,97 +0,0 @@
72.4 -/**
72.5 - * SQL-DK
72.6 - * Copyright © 2014 František Kučera (frantovo.cz)
72.7 - *
72.8 - * This program is free software: you can redistribute it and/or modify
72.9 - * it under the terms of the GNU General Public License as published by
72.10 - * the Free Software Foundation, either version 3 of the License, or
72.11 - * (at your option) any later version.
72.12 - *
72.13 - * This program is distributed in the hope that it will be useful,
72.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
72.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72.16 - * GNU General Public License for more details.
72.17 - *
72.18 - * You should have received a copy of the GNU General Public License
72.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
72.20 - */
72.21 -package info.globalcode.sql.dk.jmx;
72.22 -
72.23 -import java.util.EnumMap;
72.24 -import java.util.Map;
72.25 -
72.26 -/**
72.27 - * JMX management bean for progress reporting.
72.28 - *
72.29 - * @author Ing. František Kučera (frantovo.cz)
72.30 - */
72.31 -public class ConnectionManagement implements ConnectionManagementMBean {
72.32 -
72.33 - private final String databaseName;
72.34 - private final Map<COUNTER, Integer> counters = new EnumMap(COUNTER.class);
72.35 -
72.36 - public ConnectionManagement(String databaseName) {
72.37 - this.databaseName = databaseName;
72.38 - for (COUNTER c : COUNTER.values()) {
72.39 - counters.put(c, 0);
72.40 - }
72.41 - }
72.42 -
72.43 - public enum COUNTER {
72.44 -
72.45 - COMMAND,
72.46 - RECORD_CURRENT,
72.47 - RECORD_TOTAL
72.48 - };
72.49 -
72.50 - public void incrementCounter(COUNTER counter) {
72.51 - synchronized (counters) {
72.52 - int old = counters.get(counter);
72.53 - counters.put(counter, old + 1);
72.54 - }
72.55 - }
72.56 -
72.57 - public void resetCounter(COUNTER counter) {
72.58 - synchronized (counters) {
72.59 - counters.put(counter, 0);
72.60 - }
72.61 - }
72.62 -
72.63 - public static void incrementCounter(ConnectionManagement mbean, COUNTER counter) {
72.64 - if (mbean != null) {
72.65 - mbean.incrementCounter(counter);
72.66 - }
72.67 - }
72.68 -
72.69 - public static void resetCounter(ConnectionManagement mbean, COUNTER counter) {
72.70 - if (mbean != null) {
72.71 - mbean.resetCounter(counter);
72.72 - }
72.73 - }
72.74 -
72.75 - @Override
72.76 - public String getDatabaseName() {
72.77 - return databaseName;
72.78 - }
72.79 -
72.80 - @Override
72.81 - public int getCommandCount() {
72.82 - synchronized (counters) {
72.83 - return counters.get(COUNTER.COMMAND);
72.84 - }
72.85 - }
72.86 -
72.87 - @Override
72.88 - public int getCurrentRecordCount() {
72.89 - synchronized (counters) {
72.90 - return counters.get(COUNTER.RECORD_CURRENT);
72.91 - }
72.92 - }
72.93 -
72.94 - @Override
72.95 - public int getTotalRecordCount() {
72.96 - synchronized (counters) {
72.97 - return counters.get(COUNTER.RECORD_TOTAL);
72.98 - }
72.99 - }
72.100 -}
73.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/jmx/ConnectionManagementMBean.java Mon Mar 04 17:06:42 2019 +0100
73.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
73.3 @@ -1,34 +0,0 @@
73.4 -/**
73.5 - * SQL-DK
73.6 - * Copyright © 2014 František Kučera (frantovo.cz)
73.7 - *
73.8 - * This program is free software: you can redistribute it and/or modify
73.9 - * it under the terms of the GNU General Public License as published by
73.10 - * the Free Software Foundation, either version 3 of the License, or
73.11 - * (at your option) any later version.
73.12 - *
73.13 - * This program is distributed in the hope that it will be useful,
73.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
73.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73.16 - * GNU General Public License for more details.
73.17 - *
73.18 - * You should have received a copy of the GNU General Public License
73.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
73.20 - */
73.21 -package info.globalcode.sql.dk.jmx;
73.22 -
73.23 -/**
73.24 - *
73.25 - * @author Ing. František Kučera (frantovo.cz)
73.26 - */
73.27 -public interface ConnectionManagementMBean {
73.28 -
73.29 - public String getDatabaseName();
73.30 -
73.31 - public int getCommandCount();
73.32 -
73.33 - public int getCurrentRecordCount();
73.34 -
73.35 - public int getTotalRecordCount();
73.36 -
73.37 -}
74.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/jmx/ManagementUtils.java Mon Mar 04 17:06:42 2019 +0100
74.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
74.3 @@ -1,68 +0,0 @@
74.4 -/**
74.5 - * SQL-DK
74.6 - * Copyright © 2014 František Kučera (frantovo.cz)
74.7 - *
74.8 - * This program is free software: you can redistribute it and/or modify
74.9 - * it under the terms of the GNU General Public License as published by
74.10 - * the Free Software Foundation, either version 3 of the License, or
74.11 - * (at your option) any later version.
74.12 - *
74.13 - * This program is distributed in the hope that it will be useful,
74.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
74.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74.16 - * GNU General Public License for more details.
74.17 - *
74.18 - * You should have received a copy of the GNU General Public License
74.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
74.20 - */
74.21 -package info.globalcode.sql.dk.jmx;
74.22 -
74.23 -import java.lang.management.ManagementFactory;
74.24 -import java.util.Hashtable;
74.25 -import java.util.logging.Level;
74.26 -import java.util.logging.Logger;
74.27 -import javax.management.MBeanServer;
74.28 -import javax.management.ObjectName;
74.29 -
74.30 -/**
74.31 - *
74.32 - * @author Ing. František Kučera (frantovo.cz)
74.33 - */
74.34 -public class ManagementUtils {
74.35 -
74.36 - private static final Logger log = Logger.getLogger(ManagementUtils.class.getName());
74.37 - public static final String DEFAULT_CONNECTION_JMX_NAME = "main";
74.38 -
74.39 - /**
74.40 - * @see #registerMBean(java.lang.String, java.lang.String) with default JMX name
74.41 - */
74.42 - public static ConnectionManagement registerMBean(String dbName) {
74.43 - return registerMBean(dbName, DEFAULT_CONNECTION_JMX_NAME);
74.44 - }
74.45 -
74.46 - /**
74.47 - *
74.48 - * @param dbName database name
74.49 - * @param jmxName name of JMX bean
74.50 - * @return registered JMX bean | or null if registration fails (should not)
74.51 - */
74.52 - public static ConnectionManagement registerMBean(String dbName, String jmxName) {
74.53 - try {
74.54 - ConnectionManagement mbean = new ConnectionManagement(dbName);
74.55 - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
74.56 - Hashtable<String, String> objectProperties = new Hashtable<>();
74.57 - objectProperties.put("type", "Connection");
74.58 - objectProperties.put("name", jmxName);
74.59 - ObjectName objectName = new ObjectName("info.globalcode.sql.dk", objectProperties);
74.60 - mbs.registerMBean(mbean, objectName);
74.61 - log.log(Level.FINE, "JMX MBean was registered as: {0}", objectName);
74.62 - return mbean;
74.63 - } catch (Exception e) {
74.64 - log.log(Level.WARNING, "Unable to register JMX MBean", e);
74.65 - return null;
74.66 - }
74.67 - }
74.68 -
74.69 - private ManagementUtils() {
74.70 - }
74.71 -}
75.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/logging/ColorfulConsoleFormatter.java Mon Mar 04 17:06:42 2019 +0100
75.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
75.3 @@ -1,97 +0,0 @@
75.4 -/**
75.5 - * SQL-DK
75.6 - * Copyright © 2013 František Kučera (frantovo.cz)
75.7 - *
75.8 - * This program is free software: you can redistribute it and/or modify
75.9 - * it under the terms of the GNU General Public License as published by
75.10 - * the Free Software Foundation, either version 3 of the License, or
75.11 - * (at your option) any later version.
75.12 - *
75.13 - * This program is distributed in the hope that it will be useful,
75.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
75.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75.16 - * GNU General Public License for more details.
75.17 - *
75.18 - * You should have received a copy of the GNU General Public License
75.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
75.20 - */
75.21 -package info.globalcode.sql.dk.logging;
75.22 -
75.23 -import info.globalcode.sql.dk.ColorfulPrintWriter;
75.24 -import static info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
75.25 -import static info.globalcode.sql.dk.ColorfulPrintWriter.TerminalStyle;
75.26 -import static info.globalcode.sql.dk.Functions.rpad;
75.27 -import java.io.StringWriter;
75.28 -import java.util.logging.Formatter;
75.29 -import java.util.logging.Level;
75.30 -import java.util.logging.LogRecord;
75.31 -
75.32 -/**
75.33 - * For console/terminal log output. Log messages are printed in brief and colorful form.
75.34 - *
75.35 - * @author Ing. František Kučera (frantovo.cz)
75.36 - */
75.37 -public class ColorfulConsoleFormatter extends Formatter {
75.38 -
75.39 - private boolean printStacktrace = false;
75.40 -
75.41 - @Override
75.42 - public String format(LogRecord r) {
75.43 - StringWriter sw = new StringWriter();
75.44 - try (ColorfulPrintWriter out = new ColorfulPrintWriter(sw)) {
75.45 - printLevel(out, r.getLevel());
75.46 - printMessage(out, r);
75.47 - printThrowable(out, r);
75.48 - out.println();
75.49 - }
75.50 - return sw.toString();
75.51 - }
75.52 -
75.53 - private void printLevel(ColorfulPrintWriter out, Level l) {
75.54 - TerminalColor color = TerminalColor.Magenta;
75.55 -
75.56 - if (l == Level.SEVERE) {
75.57 - color = TerminalColor.Red;
75.58 - } else if (l == Level.WARNING) {
75.59 - color = TerminalColor.Yellow;
75.60 - }
75.61 -
75.62 - out.print(color, rpad(l.getLocalizedName() + ": ", 10));
75.63 - }
75.64 -
75.65 - private void printMessage(ColorfulPrintWriter out, LogRecord r) {
75.66 - out.print(formatMessage(r));
75.67 - }
75.68 -
75.69 - private void printThrowable(ColorfulPrintWriter out, LogRecord r) {
75.70 - Throwable t = r.getThrown();
75.71 - if (t != null) {
75.72 - out.print(": ");
75.73 - out.print(TerminalColor.Red, t.getClass().getSimpleName());
75.74 - String message = t.getLocalizedMessage();
75.75 - if (message != null) {
75.76 - out.print(": ");
75.77 - if (printStacktrace) {
75.78 - out.print(message);
75.79 - } else {
75.80 - out.print(message.replaceAll("\\n", " "));
75.81 - }
75.82 - }
75.83 - if (printStacktrace) {
75.84 - out.println();
75.85 - out.setForegroundColor(TerminalColor.Yellow);
75.86 - out.setStyle(TerminalStyle.Dim);
75.87 - t.printStackTrace(out);
75.88 - out.resetAll();
75.89 - }
75.90 - }
75.91 - }
75.92 -
75.93 - public boolean isPrintStacktrace() {
75.94 - return printStacktrace;
75.95 - }
75.96 -
75.97 - public void setPrintStacktrace(boolean printStacktrace) {
75.98 - this.printStacktrace = printStacktrace;
75.99 - }
75.100 -}
76.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/logging/LoggerInitializer.java Mon Mar 04 17:06:42 2019 +0100
76.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
76.3 @@ -1,78 +0,0 @@
76.4 -/**
76.5 - * SQL-DK
76.6 - * Copyright © 2013 František Kučera (frantovo.cz)
76.7 - *
76.8 - * This program is free software: you can redistribute it and/or modify
76.9 - * it under the terms of the GNU General Public License as published by
76.10 - * the Free Software Foundation, either version 3 of the License, or
76.11 - * (at your option) any later version.
76.12 - *
76.13 - * This program is distributed in the hope that it will be useful,
76.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
76.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76.16 - * GNU General Public License for more details.
76.17 - *
76.18 - * You should have received a copy of the GNU General Public License
76.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
76.20 - */
76.21 -package info.globalcode.sql.dk.logging;
76.22 -
76.23 -import info.globalcode.sql.dk.Constants;
76.24 -import java.util.logging.ConsoleHandler;
76.25 -import java.util.logging.Handler;
76.26 -import java.util.logging.Level;
76.27 -import java.util.logging.Logger;
76.28 -
76.29 -/**
76.30 - * Configures logging subsystem.
76.31 - * Usage: java -Djava.util.logging.config.class=info.globalcode.sql.dk.logging.LoggerInitializer …
76.32 - *
76.33 - * @author Ing. František Kučera (frantovo.cz)
76.34 - */
76.35 -public class LoggerInitializer {
76.36 -
76.37 - private static final Logger log = Logger.getLogger(LoggerInitializer.class.getName());
76.38 - public static final String LEVEL_PROPERTY = LoggerInitializer.class.getName() + ".level";
76.39 - private static final Level DEFAULT_LEVEL = Level.INFO;
76.40 -
76.41 - public LoggerInitializer() {
76.42 - Logger logger = Logger.getLogger(Constants.JAVA_PACKAGE);
76.43 - ConsoleHandler handler = new ConsoleHandler();
76.44 - ColorfulConsoleFormatter formatter = new ColorfulConsoleFormatter();
76.45 -
76.46 - logger.addHandler(handler);
76.47 - handler.setFormatter(formatter);
76.48 -
76.49 - setLevel(logger, handler, formatter);
76.50 -
76.51 -
76.52 - /**
76.53 - * TODO: optional FileHandler – detailed logs in file in ~/sql-dk/log/…
76.54 - */
76.55 - }
76.56 -
76.57 - private void setLevel(Logger logger, Handler handler, ColorfulConsoleFormatter formatter) {
76.58 - boolean levelParseError = false;
76.59 - Level level;
76.60 - String cliLevel = System.getProperty(LEVEL_PROPERTY);
76.61 - if (cliLevel == null) {
76.62 - level = DEFAULT_LEVEL;
76.63 - } else {
76.64 - try {
76.65 - level = Level.parse(cliLevel);
76.66 - } catch (IllegalArgumentException e) {
76.67 - level = DEFAULT_LEVEL;
76.68 - levelParseError = true;
76.69 - }
76.70 - }
76.71 -
76.72 - handler.setLevel(level);
76.73 - logger.setLevel(level);
76.74 -
76.75 - if (levelParseError) {
76.76 - log.log(Level.WARNING, "Invalid logging level „{0}“ specified in „{1}“ → using default level „{2}“", new Object[]{cliLevel, LEVEL_PROPERTY, DEFAULT_LEVEL});
76.77 - }
76.78 -
76.79 - formatter.setPrintStacktrace(level.intValue() < Level.INFO.intValue());
76.80 - }
76.81 -}
77.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/logging/LoggerProducer.java Mon Mar 04 17:06:42 2019 +0100
77.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
77.3 @@ -1,36 +0,0 @@
77.4 -/**
77.5 - * SQL-DK
77.6 - * Copyright © 2015 František Kučera (frantovo.cz)
77.7 - *
77.8 - * This program is free software: you can redistribute it and/or modify
77.9 - * it under the terms of the GNU General Public License as published by
77.10 - * the Free Software Foundation, either version 3 of the License, or
77.11 - * (at your option) any later version.
77.12 - *
77.13 - * This program is distributed in the hope that it will be useful,
77.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
77.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77.16 - * GNU General Public License for more details.
77.17 - *
77.18 - * You should have received a copy of the GNU General Public License
77.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
77.20 - */
77.21 -package info.globalcode.sql.dk.logging;
77.22 -
77.23 -import java.util.logging.Logger;
77.24 -
77.25 -/**
77.26 - *
77.27 - * @author Ing. František Kučera (frantovo.cz)
77.28 - */
77.29 -public class LoggerProducer {
77.30 -
77.31 - /**
77.32 - * @return created logger for the caller class
77.33 - */
77.34 - public static Logger getLogger() {
77.35 - String className = Thread.currentThread().getStackTrace()[2].getClassName();
77.36 - return Logger.getLogger(className);
77.37 - }
77.38 -
77.39 -}
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIOptions.java Mon Mar 04 20:15:24 2019 +0100
78.3 @@ -0,0 +1,283 @@
78.4 +/**
78.5 + * SQL-DK
78.6 + * Copyright © 2013 František Kučera (frantovo.cz)
78.7 + *
78.8 + * This program is free software: you can redistribute it and/or modify
78.9 + * it under the terms of the GNU General Public License as published by
78.10 + * the Free Software Foundation, either version 3 of the License, or
78.11 + * (at your option) any later version.
78.12 + *
78.13 + * This program is distributed in the hope that it will be useful,
78.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
78.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
78.16 + * GNU General Public License for more details.
78.17 + *
78.18 + * You should have received a copy of the GNU General Public License
78.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
78.20 + */
78.21 +package info.globalcode.sql.dk;
78.22 +
78.23 +import static info.globalcode.sql.dk.Functions.isNotEmpty;
78.24 +import static info.globalcode.sql.dk.Functions.equalz;
78.25 +import info.globalcode.sql.dk.InfoLister.InfoType;
78.26 +import info.globalcode.sql.dk.configuration.Properties;
78.27 +import info.globalcode.sql.dk.configuration.Property;
78.28 +import java.io.InputStream;
78.29 +import java.io.OutputStream;
78.30 +import java.util.ArrayList;
78.31 +import java.util.Collection;
78.32 +import java.util.EnumSet;
78.33 +import java.util.LinkedHashSet;
78.34 +import java.util.List;
78.35 +import java.util.Set;
78.36 +import java.util.regex.Pattern;
78.37 +import java.util.regex.PatternSyntaxException;
78.38 +
78.39 +/**
78.40 + * Holds options from command line, validates them, combines with configuration and provides derived
78.41 + * objects.
78.42 + *
78.43 + * @author Ing. František Kučera (frantovo.cz)
78.44 + */
78.45 +public class CLIOptions {
78.46 +
78.47 + public static final String DEFAULT_NAME_PREFIX = ":";
78.48 + public static final String DEFAULT_NAME_SUFFIX = "(?=([^\\w]|$))";
78.49 + private String sql;
78.50 + private String databaseName;
78.51 + private final Set<String> databaseNamesToTest = new LinkedHashSet<>();
78.52 + private final Set<String> databaseNamesToListProperties = new LinkedHashSet<>();
78.53 + private final Set<String> formatterNamesToListProperties = new LinkedHashSet<>();
78.54 + private String namePrefix = DEFAULT_NAME_PREFIX;
78.55 + private String nameSuffix = DEFAULT_NAME_SUFFIX;
78.56 + private String formatterName;
78.57 + private boolean batch;
78.58 + private final Properties formatterProperties = new Properties();
78.59 + private final Properties databaseProperties = new Properties();
78.60 +
78.61 + public enum MODE {
78.62 +
78.63 + QUERY_NOW,
78.64 + PREPARE_BATCH,
78.65 + EXECUTE_BATCH,
78.66 + JUST_SHOW_INFO
78.67 + }
78.68 + private final List<NamedParameter> namedParameters = new ArrayList<>();
78.69 + private final List<Parameter> numberedParameters = new ArrayList<>();
78.70 + private final EnumSet<InfoType> showInfo = EnumSet.noneOf(InfoType.class);
78.71 +
78.72 + public void validate() throws InvalidOptionsException {
78.73 + InvalidOptionsException e = new InvalidOptionsException();
78.74 +
78.75 + MODE mode = getMode();
78.76 + if (mode == null) {
78.77 + e.addProblem(new InvalidOptionsException.OptionProblem("Invalid combination of DB, SQL and BATCH – please specify just 2 of this 3 options"));
78.78 + } else if (mode == MODE.JUST_SHOW_INFO) {
78.79 + if (!namedParameters.isEmpty()) {
78.80 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not use named parameters if just showing info."));
78.81 + }
78.82 + if (!numberedParameters.isEmpty()) {
78.83 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not use numbered parameters if just showing info."));
78.84 + }
78.85 + if (isNotEmpty(sql, false)) {
78.86 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify SQL if just showing info."));
78.87 + }
78.88 + if (isNotEmpty(databaseName, false)) {
78.89 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify database if just showing info."));
78.90 + }
78.91 + if (batch) {
78.92 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify batch if just showing info."));
78.93 + }
78.94 + if (!equalz(namePrefix, DEFAULT_NAME_PREFIX)) {
78.95 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name prefix if just showing info."));
78.96 + }
78.97 + if (!equalz(nameSuffix, DEFAULT_NAME_SUFFIX)) {
78.98 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name suffix if just showing info."));
78.99 + }
78.100 + if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) {
78.101 + e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested."));
78.102 + }
78.103 + if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) {
78.104 + e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed."));
78.105 + }
78.106 + }
78.107 +
78.108 + if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) {
78.109 + e.addProblem(new InvalidOptionsException.OptionProblem("Named and numbered parameters can not be used together in one command."));
78.110 + }
78.111 +
78.112 + try {
78.113 + Pattern.compile(namePrefix + "test" + nameSuffix);
78.114 + } catch (PatternSyntaxException regexException) {
78.115 + e.addProblem(new InvalidOptionsException.OptionProblem("Ivalid regular expression in name prefix or suffix", regexException));
78.116 + }
78.117 +
78.118 + if (e.hasProblems()) {
78.119 + throw e;
78.120 + }
78.121 + }
78.122 +
78.123 + private boolean hasSql() {
78.124 + return isNotEmpty(getSql(), true);
78.125 + }
78.126 +
78.127 + private boolean hasDb() {
78.128 + return isNotEmpty(getDatabaseName(), true);
78.129 + }
78.130 +
78.131 + /**
78.132 + * Depends on options: DB, BATCH, SQL
78.133 + *
78.134 + * @return mode | or null if options are not yet initialized or combination of options is
78.135 + * invalid
78.136 + */
78.137 + public MODE getMode() {
78.138 + if (hasDb() && !batch && hasSql()) {
78.139 + return MODE.QUERY_NOW;
78.140 + } else if (!hasDb() && batch && hasSql()) {
78.141 + return MODE.PREPARE_BATCH;
78.142 + } else if (hasDb() && batch && !hasSql()) {
78.143 + return MODE.EXECUTE_BATCH;
78.144 + } else {
78.145 + return showInfo.isEmpty() ? null : MODE.JUST_SHOW_INFO;
78.146 + }
78.147 + }
78.148 +
78.149 + public String getSql() {
78.150 + return sql;
78.151 + }
78.152 +
78.153 + public void setSql(String sql) {
78.154 + this.sql = sql;
78.155 + }
78.156 +
78.157 + public String getDatabaseName() {
78.158 + return databaseName;
78.159 + }
78.160 +
78.161 + public void setDatabaseName(String databaseName) {
78.162 + this.databaseName = databaseName;
78.163 + }
78.164 +
78.165 + public void setBatch(boolean batch) {
78.166 + this.batch = batch;
78.167 + }
78.168 +
78.169 + public Collection<NamedParameter> getNamedParameters() {
78.170 + return namedParameters;
78.171 + }
78.172 +
78.173 + public List<Parameter> getNumberedParameters() {
78.174 + return numberedParameters;
78.175 + }
78.176 +
78.177 + public void addNumberedParameter(Parameter p) {
78.178 + numberedParameters.add(p);
78.179 + }
78.180 +
78.181 + public void addNamedParameter(NamedParameter p) {
78.182 + namedParameters.add(p);
78.183 + }
78.184 +
78.185 + public Properties getDatabaseProperties() {
78.186 + return databaseProperties;
78.187 + }
78.188 +
78.189 + public Properties getFormatterProperties() {
78.190 + return formatterProperties;
78.191 + }
78.192 +
78.193 + public void addDatabaseProperty(Property p) {
78.194 + databaseProperties.add(p);
78.195 + }
78.196 +
78.197 + public void addFormatterProperty(Property p) {
78.198 + formatterProperties.add(p);
78.199 + }
78.200 +
78.201 + /**
78.202 + * @return regular expression describing the name prefix
78.203 + */
78.204 + public String getNamePrefix() {
78.205 + return namePrefix;
78.206 + }
78.207 +
78.208 + /**
78.209 + * @param namePrefix
78.210 + * @see #getNamePrefix()
78.211 + */
78.212 + public void setNamePrefix(String namePrefix) {
78.213 + this.namePrefix = namePrefix;
78.214 + }
78.215 +
78.216 + /**
78.217 + * @return regular expression describing the name prefix
78.218 + */
78.219 + public String getNameSuffix() {
78.220 + return nameSuffix;
78.221 + }
78.222 +
78.223 + /**
78.224 + * @param nameSuffix
78.225 + * @see #getNameSuffix()
78.226 + */
78.227 + public void setNameSuffix(String nameSuffix) {
78.228 + this.nameSuffix = nameSuffix;
78.229 + }
78.230 +
78.231 + public String getFormatterName() {
78.232 + return formatterName;
78.233 + }
78.234 +
78.235 + public void setFormatterName(String formatterName) {
78.236 + this.formatterName = formatterName;
78.237 + }
78.238 +
78.239 + public void addShowInfo(InfoType info) {
78.240 + showInfo.add(info);
78.241 + }
78.242 +
78.243 + public EnumSet<InfoType> getShowInfo() {
78.244 + return showInfo;
78.245 + }
78.246 +
78.247 + public Set<String> getDatabaseNamesToTest() {
78.248 + return databaseNamesToTest;
78.249 + }
78.250 +
78.251 + public void addDatabaseNameToTest(String name) {
78.252 + databaseNamesToTest.add(name);
78.253 + }
78.254 +
78.255 + public Set<String> getDatabaseNamesToListProperties() {
78.256 + return databaseNamesToListProperties;
78.257 + }
78.258 +
78.259 + public void addDatabaseNameToListProperties(String name) {
78.260 + databaseNamesToListProperties.add(name);
78.261 + }
78.262 +
78.263 + public Set<String> getFormatterNamesToListProperties() {
78.264 + return formatterNamesToListProperties;
78.265 + }
78.266 +
78.267 + public void addFormatterNameToListProperties(String name) {
78.268 + formatterNamesToListProperties.add(name);
78.269 + }
78.270 +
78.271 + public SQLCommand getSQLCommand() {
78.272 + if (namedParameters.isEmpty()) {
78.273 + return new SQLCommandNumbered(sql, numberedParameters);
78.274 + } else {
78.275 + return new SQLCommandNamed(sql, namedParameters, namePrefix, nameSuffix);
78.276 + }
78.277 + }
78.278 +
78.279 + public OutputStream getOutputStream() {
78.280 + return System.out;
78.281 + }
78.282 +
78.283 + public InputStream getInputStream() {
78.284 + return System.in;
78.285 + }
78.286 +}
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIParser.java Mon Mar 04 20:15:24 2019 +0100
79.3 @@ -0,0 +1,216 @@
79.4 +/**
79.5 + * SQL-DK
79.6 + * Copyright © 2013 František Kučera (frantovo.cz)
79.7 + *
79.8 + * This program is free software: you can redistribute it and/or modify
79.9 + * it under the terms of the GNU General Public License as published by
79.10 + * the Free Software Foundation, either version 3 of the License, or
79.11 + * (at your option) any later version.
79.12 + *
79.13 + * This program is distributed in the hope that it will be useful,
79.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79.16 + * GNU General Public License for more details.
79.17 + *
79.18 + * You should have received a copy of the GNU General Public License
79.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
79.20 + */
79.21 +package info.globalcode.sql.dk;
79.22 +
79.23 +import static info.globalcode.sql.dk.Functions.readString;
79.24 +import info.globalcode.sql.dk.InfoLister.InfoType;
79.25 +import info.globalcode.sql.dk.configuration.Property;
79.26 +import java.io.IOException;
79.27 +import java.io.InputStream;
79.28 +import java.util.ArrayList;
79.29 +import java.util.HashMap;
79.30 +import java.util.List;
79.31 +import java.util.Map;
79.32 +
79.33 +/**
79.34 + * Converts command line arguments from String array to object.
79.35 + * Checks basic constraints (if only supported options are used and if they have correct number of
79.36 + * parameters)
79.37 + *
79.38 + * @author Ing. František Kučera (frantovo.cz)
79.39 + */
79.40 +public class CLIParser {
79.41 +
79.42 + public static final String TYPE_NAME_SEPARATOR = ":";
79.43 +
79.44 + public CLIOptions parseOptions(String[] args, InputStream in) throws CLIParserException {
79.45 + CLIOptions options = new CLIOptions();
79.46 +
79.47 + List<SQLType> numberedTypes = new ArrayList<>();
79.48 + Map<String, SQLType> namedTypes = new HashMap<>();
79.49 +
79.50 + for (int i = 0; i < args.length; i++) {
79.51 + String arg = args[i];
79.52 + switch (arg) {
79.53 + case Tokens.TYPES:
79.54 + String typesString = fetchNext(args, ++i);
79.55 +
79.56 + for (String oneType : typesString.split(",")) {
79.57 + int sepatratorIndex = oneType.indexOf(TYPE_NAME_SEPARATOR);
79.58 + if (sepatratorIndex == -1) {
79.59 + numberedTypes.add(getType(oneType.toUpperCase()));
79.60 + } else {
79.61 + String namePart = oneType.substring(0, sepatratorIndex).trim();
79.62 + String typePart = oneType.substring(sepatratorIndex + TYPE_NAME_SEPARATOR.length(), oneType.length());
79.63 + namedTypes.put(namePart, getType(typePart.toUpperCase()));
79.64 + }
79.65 + }
79.66 + break;
79.67 + case Tokens.NAME_PREFIX:
79.68 + options.setNamePrefix(fetchNext(args, ++i));
79.69 + break;
79.70 + case Tokens.NAME_SUFFIX:
79.71 + options.setNameSuffix(fetchNext(args, ++i));
79.72 + break;
79.73 + case Tokens.DB:
79.74 + options.setDatabaseName(fetchNext(args, ++i));
79.75 + break;
79.76 + case Tokens.SQL:
79.77 + options.setSql(fetchNext(args, ++i));
79.78 + break;
79.79 + case Tokens.SQL_IN:
79.80 + try {
79.81 + options.setSql(readString(in));
79.82 + } catch (IOException e) {
79.83 + throw new CLIParserException("Unable to read SQL from the input stream", e);
79.84 + }
79.85 + break;
79.86 + case Tokens.BATCH:
79.87 + options.setBatch(true);
79.88 + break;
79.89 + case Tokens.DATA: // --data is the last option
79.90 + for (i++; i < args.length; i++) {
79.91 + arg = args[i];
79.92 + Parameter parameter;
79.93 + if (numberedTypes.isEmpty()) {
79.94 + parameter = new Parameter(arg, null);
79.95 + } else {
79.96 + int paramIndex = options.getNumberedParameters().size();
79.97 + SQLType paramType;
79.98 + try {
79.99 + paramType = numberedTypes.get(paramIndex);
79.100 + } catch (IndexOutOfBoundsException e) {
79.101 + throw new CLIParserException("Missing type for parameter #" + paramIndex, e);
79.102 + } catch (NullPointerException e) {
79.103 + throw new CLIParserException("Invalid type definition for parameter #" + paramIndex, e);
79.104 + }
79.105 + parameter = new Parameter(arg, paramType);
79.106 + }
79.107 + options.addNumberedParameter(parameter);
79.108 + }
79.109 + break;
79.110 + case Tokens.DATA_NAMED:
79.111 + for (i++; i < args.length; i++) {
79.112 + String paramName = args[i];
79.113 + String paramValue = fetchNext(args, ++i);
79.114 + options.addNamedParameter(new NamedParameter(paramName, paramValue, namedTypes.get(paramName)));
79.115 + }
79.116 + break;
79.117 + case Tokens.FORMATTER:
79.118 + options.setFormatterName(fetchNext(args, ++i));
79.119 + break;
79.120 + case Tokens.DB_PROPERTY:
79.121 + options.addDatabaseProperty(new Property(fetchNext(args, ++i), fetchNext(args, ++i)));
79.122 + break;
79.123 + case Tokens.FORMATTER_PROPERTY:
79.124 + options.addFormatterProperty(new Property(fetchNext(args, ++i), fetchNext(args, ++i)));
79.125 + break;
79.126 + case Tokens.INFO_HELP:
79.127 + options.addShowInfo(InfoType.HELP);
79.128 + break;
79.129 + case Tokens.INFO_FORMATTERS:
79.130 + options.addShowInfo(InfoType.FORMATTERS);
79.131 + break;
79.132 + case Tokens.INFO_FORMATTER_PROPERTIES:
79.133 + options.addShowInfo(InfoType.FORMATTER_PROPERTIES);
79.134 + options.addFormatterNameToListProperties(fetchNext(args, ++i));
79.135 + break;
79.136 + case Tokens.INFO_LICENSE:
79.137 + options.addShowInfo(InfoType.LICENSE);
79.138 + break;
79.139 + case Tokens.INFO_JAVA_PROPERTIES:
79.140 + options.addShowInfo(InfoType.JAVA_PROPERTIES);
79.141 + break;
79.142 + case Tokens.INFO_ENVIRONMENT_VARIABLES:
79.143 + options.addShowInfo(InfoType.ENVIRONMENT_VARIABLES);
79.144 + break;
79.145 + case Tokens.INFO_TYPES:
79.146 + options.addShowInfo(InfoType.TYPES);
79.147 + break;
79.148 + case Tokens.INFO_VERSION:
79.149 + options.addShowInfo(InfoType.VERSION);
79.150 + break;
79.151 + case Tokens.INFO_JDBC_DRIVERS:
79.152 + options.addShowInfo(InfoType.JDBC_DRIVERS);
79.153 + break;
79.154 + case Tokens.INFO_JDBC_PROPERTIES:
79.155 + options.addShowInfo(InfoType.JDBC_PROPERTIES);
79.156 + options.addDatabaseNameToListProperties(fetchNext(args, ++i));
79.157 + break;
79.158 + case Tokens.INFO_DATABASES:
79.159 + options.addShowInfo(InfoType.DATABASES);
79.160 + break;
79.161 + case Tokens.INFO_CONNECTION:
79.162 + options.addShowInfo(InfoType.CONNECTION);
79.163 + options.addDatabaseNameToTest(fetchNext(args, ++i));
79.164 + break;
79.165 + default:
79.166 + throw new CLIParserException("Unknown option: " + arg);
79.167 + }
79.168 + }
79.169 + return options;
79.170 + }
79.171 +
79.172 + private String fetchNext(String[] args, int index) throws CLIParserException {
79.173 + if (index < args.length) {
79.174 + return args[index];
79.175 + } else {
79.176 + throw new CLIParserException("Expecting value for option: " + args[index - 1]);
79.177 + }
79.178 + }
79.179 +
79.180 + public static class Tokens {
79.181 +
79.182 + // bash-completion:options:
79.183 + public static final String DB = "--db"; // bash-completion:option // help: database name
79.184 + public static final String DB_PROPERTY = "--db-property"; // bash-completion:option // help: name and value
79.185 + public static final String SQL = "--sql"; // bash-completion:option // help: SQL query/command
79.186 + public static final String SQL_IN = "--sql-in"; // bash-completion:option // help: SQL query/command
79.187 + public static final String BATCH = "--batch"; // bash-completion:option // help: batch mode (no argument)
79.188 + public static final String DATA = "--data"; // bash-completion:option // help: list of ordinal parameters
79.189 + public static final String DATA_NAMED = "--data-named"; // bash-completion:option // help: list of named parameters
79.190 + public static final String NAME_PREFIX = "--name-prefix"; // bash-completion:option // help: parameter name prefix – regular expression
79.191 + public static final String NAME_SUFFIX = "--name-suffix"; // bash-completion:option // help: parameter name suffix – regular expression
79.192 + public static final String TYPES = "--types"; // bash-completion:option // help: comma separated list of parameter types
79.193 + public static final String FORMATTER = "--formatter"; // bash-completion:option // help: name of the output formatter
79.194 + public static final String FORMATTER_PROPERTY = "--formatter-property"; // bash-completion:option // help: name and value
79.195 + public static final String INFO_HELP = "--help"; // bash-completion:option // help: print this help
79.196 + public static final String INFO_VERSION = "--version"; // bash-completion:option // help: print version info
79.197 + public static final String INFO_LICENSE = "--license"; // bash-completion:option // help: print license
79.198 + public static final String INFO_JAVA_PROPERTIES = "--list-java-properties"; // bash-completion:option // help: list of Java system properties
79.199 + public static final String INFO_ENVIRONMENT_VARIABLES = "--list-environment-variables"; // bash-completion:option // help: list of environment variables
79.200 + public static final String INFO_FORMATTERS = "--list-formatters"; // bash-completion:option // help: print list of available formatters
79.201 + public static final String INFO_FORMATTER_PROPERTIES = "--list-formatter-properties"; // bash-completion:option // help: print list of available properties for given formatter
79.202 + public static final String INFO_TYPES = "--list-types"; // bash-completion:option // help: print list of available data types
79.203 + public static final String INFO_JDBC_DRIVERS = "--list-jdbc-drivers"; // bash-completion:option // help: list of available JDBC drivers
79.204 + public static final String INFO_JDBC_PROPERTIES = "--list-jdbc-properties"; // bash-completion:option // help: list of available JDBC properties for given database
79.205 + public static final String INFO_DATABASES = "--list-databases"; // bash-completion:option // help: print list of configured databases
79.206 + public static final String INFO_CONNECTION = "--test-connection"; // bash-completion:option // help: test connection to particular database
79.207 +
79.208 + private Tokens() {
79.209 + }
79.210 + }
79.211 +
79.212 + private SQLType getType(String typeString) throws CLIParserException {
79.213 + try {
79.214 + return SQLType.valueOf(typeString.trim());
79.215 + } catch (IllegalArgumentException e) {
79.216 + throw new CLIParserException("Unsupported type: " + typeString, e);
79.217 + }
79.218 + }
79.219 +}
80.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIParserException.java Mon Mar 04 20:15:24 2019 +0100
80.3 @@ -0,0 +1,40 @@
80.4 +/**
80.5 + * SQL-DK
80.6 + * Copyright © 2013 František Kučera (frantovo.cz)
80.7 + *
80.8 + * This program is free software: you can redistribute it and/or modify
80.9 + * it under the terms of the GNU General Public License as published by
80.10 + * the Free Software Foundation, either version 3 of the License, or
80.11 + * (at your option) any later version.
80.12 + *
80.13 + * This program is distributed in the hope that it will be useful,
80.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
80.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
80.16 + * GNU General Public License for more details.
80.17 + *
80.18 + * You should have received a copy of the GNU General Public License
80.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
80.20 + */
80.21 +package info.globalcode.sql.dk;
80.22 +
80.23 +/**
80.24 + *
80.25 + * @author Ing. František Kučera (frantovo.cz)
80.26 + */
80.27 +public class CLIParserException extends DKException {
80.28 +
80.29 + public CLIParserException() {
80.30 + }
80.31 +
80.32 + public CLIParserException(String message) {
80.33 + super(message);
80.34 + }
80.35 +
80.36 + public CLIParserException(Throwable cause) {
80.37 + super(cause);
80.38 + }
80.39 +
80.40 + public CLIParserException(String message, Throwable cause) {
80.41 + super(message, cause);
80.42 + }
80.43 +}
81.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
81.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIStarter.java Mon Mar 04 20:15:24 2019 +0100
81.3 @@ -0,0 +1,274 @@
81.4 +/**
81.5 + * SQL-DK
81.6 + * Copyright © 2013 František Kučera (frantovo.cz)
81.7 + *
81.8 + * This program is free software: you can redistribute it and/or modify
81.9 + * it under the terms of the GNU General Public License as published by
81.10 + * the Free Software Foundation, either version 3 of the License, or
81.11 + * (at your option) any later version.
81.12 + *
81.13 + * This program is distributed in the hope that it will be useful,
81.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
81.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
81.16 + * GNU General Public License for more details.
81.17 + *
81.18 + * You should have received a copy of the GNU General Public License
81.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
81.20 + */
81.21 +package info.globalcode.sql.dk;
81.22 +
81.23 +import info.globalcode.sql.dk.configuration.ConfigurationProvider;
81.24 +import info.globalcode.sql.dk.CLIOptions.MODE;
81.25 +import info.globalcode.sql.dk.batch.Batch;
81.26 +import info.globalcode.sql.dk.batch.BatchDecoder;
81.27 +import info.globalcode.sql.dk.batch.BatchException;
81.28 +import info.globalcode.sql.dk.batch.BatchEncoder;
81.29 +import info.globalcode.sql.dk.configuration.Configuration;
81.30 +import info.globalcode.sql.dk.configuration.ConfigurationException;
81.31 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
81.32 +import info.globalcode.sql.dk.configuration.FormatterDefinition;
81.33 +import info.globalcode.sql.dk.configuration.Loader;
81.34 +import info.globalcode.sql.dk.configuration.NameIdentified;
81.35 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
81.36 +import info.globalcode.sql.dk.formatting.Formatter;
81.37 +import info.globalcode.sql.dk.formatting.FormatterContext;
81.38 +import info.globalcode.sql.dk.formatting.FormatterException;
81.39 +import info.globalcode.sql.dk.jmx.ConnectionManagement;
81.40 +import info.globalcode.sql.dk.jmx.ManagementUtils;
81.41 +import java.io.File;
81.42 +import java.io.FileNotFoundException;
81.43 +import java.io.IOException;
81.44 +import java.io.PrintStream;
81.45 +import java.io.PrintWriter;
81.46 +import java.sql.SQLException;
81.47 +import java.util.Collection;
81.48 +import java.util.Collections;
81.49 +import java.util.List;
81.50 +import java.util.logging.Level;
81.51 +import java.util.logging.LogRecord;
81.52 +import java.util.logging.Logger;
81.53 +
81.54 +/**
81.55 + * Entry point of the command line interface of SQL-DK.
81.56 + *
81.57 + * @author Ing. František Kučera (frantovo.cz)
81.58 + */
81.59 +public class CLIStarter implements ConfigurationProvider {
81.60 +
81.61 + // help:exit-codes
81.62 + public static final int EXIT_SUCCESS = 0; // doc:success
81.63 + public static final int EXIT_UNEXPECTED_ERROR = 1; // doc:unexpected error (probably bug)
81.64 + // 2 is reserved: http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF
81.65 + public static final int EXIT_SQL_ERROR = 3; // doc:SQL error
81.66 + public static final int EXIT_CLI_PARSE_ERROR = 4; // doc:CLI options parse error
81.67 + public static final int EXIT_CLI_VALIDATE_ERROR = 5; // doc:CLI options validation error
81.68 + public static final int EXIT_CONFIGURATION_ERROR = 6; // doc:configuration error
81.69 + public static final int EXIT_FORMATTING_ERROR = 7; // doc:formatting error
81.70 + public static final int EXIT_BATCH_ERROR = 8; // doc:batch error
81.71 + private static final Logger log = Logger.getLogger(CLIStarter.class.getName());
81.72 + private final CLIOptions options;
81.73 + private final Loader configurationLoader = new Loader();
81.74 + private Configuration configuration;
81.75 +
81.76 + public static void main(String[] args) {
81.77 + log.log(Level.FINE, "Starting " + Constants.PROGRAM_NAME);
81.78 + int exitCode;
81.79 +
81.80 + if (args.length == 0) {
81.81 + args = new String[]{CLIParser.Tokens.INFO_HELP};
81.82 + }
81.83 +
81.84 + try {
81.85 + CLIParser parser = new CLIParser();
81.86 + CLIOptions options = parser.parseOptions(args, System.in);
81.87 + options.validate();
81.88 + CLIStarter starter = new CLIStarter(options);
81.89 + starter.installDefaultConfiguration();
81.90 + starter.process();
81.91 + log.log(Level.FINE, "All done");
81.92 + exitCode = EXIT_SUCCESS;
81.93 + } catch (CLIParserException e) {
81.94 + log.log(Level.SEVERE, "Unable to parse CLI options", e);
81.95 + exitCode = EXIT_CLI_PARSE_ERROR;
81.96 + } catch (InvalidOptionsException e) {
81.97 + log.log(Level.SEVERE, "Invalid CLI options", e);
81.98 + for (InvalidOptionsException.OptionProblem p : e.getProblems()) {
81.99 + LogRecord r = new LogRecord(Level.SEVERE, "Option problem: {0}");
81.100 + r.setThrown(p.getException());
81.101 + r.setParameters(new Object[]{p.getDescription()});
81.102 + log.log(r);
81.103 + }
81.104 + exitCode = EXIT_CLI_VALIDATE_ERROR;
81.105 + } catch (ConfigurationException e) {
81.106 + log.log(Level.SEVERE, "Configuration problem", e);
81.107 + exitCode = EXIT_CONFIGURATION_ERROR;
81.108 + } catch (SQLException e) {
81.109 + log.log(Level.SEVERE, "SQL problem", e);
81.110 + exitCode = EXIT_SQL_ERROR;
81.111 + } catch (FormatterException e) {
81.112 + log.log(Level.SEVERE, "Formatting problem", e);
81.113 + exitCode = EXIT_FORMATTING_ERROR;
81.114 + } catch (BatchException e) {
81.115 + log.log(Level.SEVERE, "Batch problem", e);
81.116 + exitCode = EXIT_BATCH_ERROR;
81.117 + }
81.118 +
81.119 + System.exit(exitCode);
81.120 + }
81.121 +
81.122 + public CLIStarter(CLIOptions options) {
81.123 + this.options = options;
81.124 + }
81.125 +
81.126 + private void process() throws ConfigurationException, SQLException, FormatterException, BatchException {
81.127 + MODE mode = options.getMode();
81.128 +
81.129 + /** Show info */
81.130 + if (!options.getShowInfo().isEmpty()) {
81.131 + PrintStream infoOut = mode == MODE.JUST_SHOW_INFO ? System.out : System.err;
81.132 + InfoLister infoLister = new InfoLister(infoOut, this, options);
81.133 + infoLister.showInfo();
81.134 + }
81.135 +
81.136 + switch (mode) {
81.137 + case QUERY_NOW:
81.138 + processQueryNow();
81.139 + break;
81.140 + case PREPARE_BATCH:
81.141 + processPrepareBatch();
81.142 + break;
81.143 + case EXECUTE_BATCH:
81.144 + processExecuteBatch();
81.145 + break;
81.146 + case JUST_SHOW_INFO:
81.147 + // already done above
81.148 + break;
81.149 + default:
81.150 + log.log(Level.SEVERE, "Unsupported mode: {0}", mode);
81.151 + break;
81.152 + }
81.153 +
81.154 + generateBashCompletion();
81.155 + }
81.156 +
81.157 + private void processQueryNow() throws ConfigurationException, SQLException, FormatterException {
81.158 + DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName());
81.159 + FormatterDefinition fd = configuration.getFormatter(options.getFormatterName());
81.160 + ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName());
81.161 +
81.162 + try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) {
81.163 + log.log(Level.FINE, "Database connected");
81.164 + try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) {
81.165 + c.executeQuery(options.getSQLCommand(), f);
81.166 + }
81.167 + }
81.168 + }
81.169 +
81.170 + private void processPrepareBatch() throws BatchException {
81.171 + BatchEncoder enc = new BatchEncoder();
81.172 + int length = enc.encode(options.getSQLCommand(), options.getOutputStream());
81.173 + log.log(Level.FINE, "Prepared batch size: {0} bytes", length);
81.174 + }
81.175 +
81.176 + private void processExecuteBatch() throws ConfigurationException, SQLException, FormatterException, BatchException {
81.177 + BatchDecoder dec = new BatchDecoder();
81.178 + Batch b = dec.decode(options.getInputStream());
81.179 +
81.180 + DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName());
81.181 + FormatterDefinition fd = configuration.getFormatter(options.getFormatterName());
81.182 + ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName());
81.183 +
81.184 + try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) {
81.185 + log.log(Level.FINE, "Database connected");
81.186 + try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) {
81.187 + c.executeBatch(b, f);
81.188 + }
81.189 + }
81.190 + }
81.191 +
81.192 + @Override
81.193 + public Configuration getConfiguration() throws ConfigurationException {
81.194 + if (configuration == null) {
81.195 + configuration = configurationLoader.loadConfiguration();
81.196 + }
81.197 + return configuration;
81.198 + }
81.199 +
81.200 + private void installDefaultConfiguration() throws ConfigurationException {
81.201 + Constants.DIR.mkdir();
81.202 +
81.203 + if (Constants.CONFIG_FILE.exists()) {
81.204 + log.log(Level.FINER, "Config file already exists: {0}", Constants.CONFIG_FILE);
81.205 + } else {
81.206 + try {
81.207 + Functions.installResource(Constants.EXAMPLE_CONFIG_FILE, Constants.CONFIG_FILE);
81.208 + log.log(Level.FINE, "Installing default config file: {0}", Constants.CONFIG_FILE);
81.209 + } catch (IOException e) {
81.210 + throw new ConfigurationException("Unable to write example configuration to " + Constants.CONFIG_FILE, e);
81.211 + }
81.212 + }
81.213 + }
81.214 +
81.215 + private void generateBashCompletion() {
81.216 + if (configuration == null) {
81.217 + log.log(Level.FINER, "Not writing Bash completion helper files. In order to generate these files please run some command which requires configuration.");
81.218 + } else {
81.219 + try {
81.220 + File dir = new File(Constants.DIR, "bash-completion");
81.221 + dir.mkdir();
81.222 + writeBashCompletionHelperFile(configuration.getDatabases(), new File(dir, "databases"));
81.223 + writeBashCompletionHelperFile(configuration.getAllFormatters(), new File(dir, "formatters"));
81.224 + writeBashCompletionHelperFileForFormatterProperties(new File(dir, "formatter-properties"));
81.225 + } catch (Exception e) {
81.226 + log.log(Level.WARNING, "Unable to generate Bash completion helper files", e);
81.227 + }
81.228 + }
81.229 + }
81.230 +
81.231 + private void writeBashCompletionHelperFile(Collection<? extends NameIdentified> items, File target) throws FileNotFoundException {
81.232 + if (Constants.CONFIG_FILE.lastModified() > target.lastModified()) {
81.233 + try (PrintWriter fw = new PrintWriter(target)) {
81.234 + for (NameIdentified dd : items) {
81.235 + fw.println(dd.getName());
81.236 + }
81.237 + fw.close();
81.238 + log.log(Level.FINE, "Bash completion helper file was written: {0}", target);
81.239 + }
81.240 + } else {
81.241 + log.log(Level.FINER, "Not writing Bash completion helper file: {0} because configuration {1} has not been changed", new Object[]{target, Constants.CONFIG_FILE});
81.242 + }
81.243 + }
81.244 +
81.245 + private void writeBashCompletionHelperFileForFormatterProperties(File formattersDir) throws ClassNotFoundException, FileNotFoundException {
81.246 + if (Constants.CONFIG_FILE.lastModified() > formattersDir.lastModified()) {
81.247 + // TODO: delete old directory
81.248 + formattersDir.mkdir();
81.249 + for (FormatterDefinition fd : configuration.getAllFormatters()) {
81.250 + File formatterDir = new File(formattersDir, fd.getName());
81.251 + formatterDir.mkdir();
81.252 +
81.253 + Class<Formatter> formatterClass = (Class<Formatter>) Class.forName(fd.getClassName());
81.254 + List<Class<? extends Formatter>> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class);
81.255 + Collections.reverse(hierarchy);
81.256 + for (Class<? extends Formatter> c : hierarchy) {
81.257 + for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) {
81.258 + File propertyDir = new File(formatterDir, p.name());
81.259 + propertyDir.mkdir();
81.260 + File choicesFile = new File(propertyDir, "choices");
81.261 + try (PrintWriter fw = new PrintWriter(choicesFile)) {
81.262 + // TODO: refactor, move
81.263 + if (p.type() == Boolean.class) {
81.264 + fw.println("true");
81.265 + fw.println("false");
81.266 + }
81.267 + }
81.268 + }
81.269 + }
81.270 + }
81.271 + log.log(Level.FINE, "Bash completion helper files was written in: {0}", formattersDir);
81.272 + } else {
81.273 + log.log(Level.FINER, "Not writing Bash completion helper directory: {0} because configuration {1} has not been changed", new Object[]{formattersDir, Constants.CONFIG_FILE});
81.274 + }
81.275 +
81.276 + }
81.277 +}
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/ColorfulPrintWriter.java Mon Mar 04 20:15:24 2019 +0100
82.3 @@ -0,0 +1,358 @@
82.4 +/**
82.5 + * SQL-DK
82.6 + * Copyright © 2013 František Kučera (frantovo.cz)
82.7 + *
82.8 + * This program is free software: you can redistribute it and/or modify
82.9 + * it under the terms of the GNU General Public License as published by
82.10 + * the Free Software Foundation, either version 3 of the License, or
82.11 + * (at your option) any later version.
82.12 + *
82.13 + * This program is distributed in the hope that it will be useful,
82.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
82.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82.16 + * GNU General Public License for more details.
82.17 + *
82.18 + * You should have received a copy of the GNU General Public License
82.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
82.20 + */
82.21 +package info.globalcode.sql.dk;
82.22 +
82.23 +import java.io.File;
82.24 +import java.io.FileNotFoundException;
82.25 +import java.io.OutputStream;
82.26 +import java.io.PrintWriter;
82.27 +import java.io.UnsupportedEncodingException;
82.28 +import java.io.Writer;
82.29 +import java.util.EnumSet;
82.30 +
82.31 +/**
82.32 + * PrintWriter with convenience methods for printing color and formatted text.
82.33 + *
82.34 + * Uses ANSI Escape Sequences.
82.35 + * See: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
82.36 + *
82.37 + * @author Ing. František Kučera (frantovo.cz)
82.38 + */
82.39 +public class ColorfulPrintWriter extends PrintWriter {
82.40 +
82.41 + public enum TerminalColor {
82.42 +
82.43 + Black(30, 40),
82.44 + Red(31, 41),
82.45 + Green(32, 42),
82.46 + Yellow(33, 43),
82.47 + Blue(34, 44),
82.48 + Magenta(35, 45),
82.49 + Cyan(36, 46),
82.50 + White(37, 47);
82.51 + private final int foregroundCode;
82.52 + private final int backgroundCode;
82.53 +
82.54 + private TerminalColor(int foregroundCode, int backgroundCode) {
82.55 + this.foregroundCode = foregroundCode;
82.56 + this.backgroundCode = backgroundCode;
82.57 + }
82.58 +
82.59 + public int getForegroundCode() {
82.60 + return foregroundCode;
82.61 + }
82.62 +
82.63 + public int getBackgroundCode() {
82.64 + return backgroundCode;
82.65 + }
82.66 + }
82.67 +
82.68 + public enum TerminalStyle {
82.69 +
82.70 + Reset(0),
82.71 + Bright(1),
82.72 + Dim(2),
82.73 + Underscore(4),
82.74 + Blink(5),
82.75 + Reverse(7),
82.76 + Hidden(8);
82.77 + private int code;
82.78 +
82.79 + private TerminalStyle(int code) {
82.80 + this.code = code;
82.81 + }
82.82 +
82.83 + public int getCode() {
82.84 + return code;
82.85 + }
82.86 + }
82.87 + private final boolean COLOR_ENABLED;
82.88 + private boolean colorful = true;
82.89 +
82.90 + public void setStyle(TerminalStyle style) {
82.91 + setStyle(EnumSet.of(style));
82.92 + }
82.93 +
82.94 + public void setStyle(EnumSet<TerminalStyle> styles) {
82.95 + printCodes(getStyleCodes(styles));
82.96 + }
82.97 +
82.98 + private static int[] getStyleCodes(EnumSet<TerminalStyle> styles) {
82.99 + int[] array = new int[styles.size()];
82.100 + int i = 0;
82.101 + for (TerminalStyle s : styles) {
82.102 + array[i++] = s.getCode();
82.103 + }
82.104 + return array;
82.105 + }
82.106 +
82.107 + /**
82.108 + * Print (usually audible) bell code (\007, \a, ^G)
82.109 + */
82.110 + public void bell() {
82.111 + print("\007");
82.112 + }
82.113 +
82.114 + /**
82.115 + * Eat the last character
82.116 + */
82.117 + public void backspace() {
82.118 + print("\b");
82.119 + }
82.120 +
82.121 + /**
82.122 + * Eat n last characters
82.123 + *
82.124 + * @param count n
82.125 + */
82.126 + public void backspace(int count) {
82.127 + for (int i = 0; i < count; i++) {
82.128 + backspace();
82.129 + }
82.130 + }
82.131 +
82.132 + /**
82.133 + * With 100 ms delay and all colors.
82.134 + *
82.135 + * @see #printRainbow(java.lang.String, int,
82.136 + * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[])
82.137 + */
82.138 + public void printRainbow(String string) {
82.139 + printRainbow(string, 100);
82.140 + }
82.141 +
82.142 + /**
82.143 + * With all colors.
82.144 + *
82.145 + * @see #printRainbow(java.lang.String, int,
82.146 + * info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor[])
82.147 + */
82.148 + public void printRainbow(String string, int delay) {
82.149 + printRainbow(string, delay, TerminalColor.values());
82.150 + }
82.151 +
82.152 + /**
82.153 + * Prints rainbow text – (re)writes same text subsequently in given colors and then in default
82.154 + * color.
82.155 + *
82.156 + * @param string text to be printed, should not contain \n new line (then rainbow does not work
82.157 + * – use println() after printRainbow() instead)
82.158 + * @param delay delay between rewrites
82.159 + * @param colors list of colors to be used
82.160 + */
82.161 + public void printRainbow(String string, int delay, TerminalColor... colors) {
82.162 + for (TerminalColor c : colors) {
82.163 + print(c, string);
82.164 + try {
82.165 + Thread.sleep(delay);
82.166 + } catch (InterruptedException e) {
82.167 + // no time to sleep
82.168 + break;
82.169 + }
82.170 + backspace(string.length());
82.171 + flush();
82.172 + }
82.173 + print(string);
82.174 + }
82.175 +
82.176 + public void setForegroundColor(TerminalColor color) {
82.177 + printCodes(color.getForegroundCode());
82.178 + }
82.179 +
82.180 + public void setBackgroundColor(TerminalColor color) {
82.181 + printCodes(color.getBackgroundCode());
82.182 + }
82.183 +
82.184 + public void print(TerminalColor foregroundColor, String string) {
82.185 + setForegroundColor(foregroundColor);
82.186 + print(string);
82.187 + resetAll();
82.188 + }
82.189 +
82.190 + public void println(TerminalColor foregroundColor, String string) {
82.191 + print(foregroundColor, string);
82.192 + println();
82.193 + }
82.194 +
82.195 + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) {
82.196 + setForegroundColor(foregroundColor);
82.197 + setBackgroundColor(backgroundColor);
82.198 + print(string);
82.199 + resetAll();
82.200 + }
82.201 +
82.202 + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, String string) {
82.203 + print(foregroundColor, backgroundColor, string);
82.204 + println();
82.205 + }
82.206 +
82.207 + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet<TerminalStyle> styles, String string) {
82.208 + setForegroundColor(foregroundColor);
82.209 + setBackgroundColor(backgroundColor);
82.210 + setStyle(styles);
82.211 + print(string);
82.212 + resetAll();
82.213 + }
82.214 +
82.215 + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, EnumSet<TerminalStyle> styles, String string) {
82.216 + print(foregroundColor, backgroundColor, styles, string);
82.217 + println();
82.218 + }
82.219 +
82.220 + public void print(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) {
82.221 + print(foregroundColor, backgroundColor, EnumSet.of(style), string);
82.222 + }
82.223 +
82.224 + public void println(TerminalColor foregroundColor, TerminalColor backgroundColor, TerminalStyle style, String string) {
82.225 + print(foregroundColor, backgroundColor, style, string);
82.226 + println();
82.227 + }
82.228 +
82.229 + public void print(TerminalColor foregroundColor, EnumSet<TerminalStyle> styles, String string) {
82.230 + setForegroundColor(foregroundColor);
82.231 + setStyle(styles);
82.232 + print(string);
82.233 + resetAll();
82.234 + }
82.235 +
82.236 + public void println(TerminalColor foregroundColor, EnumSet<TerminalStyle> styles, String string) {
82.237 + print(foregroundColor, styles, string);
82.238 + println();
82.239 + }
82.240 +
82.241 + public void print(TerminalColor foregroundColor, TerminalStyle style, String string) {
82.242 + print(foregroundColor, EnumSet.of(style), string);
82.243 + }
82.244 +
82.245 + public void println(TerminalColor foregroundColor, TerminalStyle style, String string) {
82.246 + print(foregroundColor, style, string);
82.247 + println();
82.248 + }
82.249 +
82.250 + public void print(EnumSet<TerminalStyle> styles, String string) {
82.251 + setStyle(styles);
82.252 + print(string);
82.253 + resetAll();
82.254 + }
82.255 +
82.256 + public void println(EnumSet<TerminalStyle> styles, String string) {
82.257 + print(styles, string);
82.258 + println();
82.259 + }
82.260 +
82.261 + public void print(TerminalStyle style, String string) {
82.262 + print(EnumSet.of(style), string);
82.263 + }
82.264 +
82.265 + public void println(TerminalStyle style, String string) {
82.266 + print(style, string);
82.267 + println();
82.268 + }
82.269 +
82.270 + public void resetAll() {
82.271 + printCodes(TerminalStyle.Reset.code);
82.272 + }
82.273 +
82.274 + private void printCodes(int... codes) {
82.275 + if (COLOR_ENABLED && colorful) {
82.276 + print("\033[");
82.277 + for (int i = 0; i < codes.length; i++) {
82.278 + print(codes[i]);
82.279 + if (i < codes.length - 1 && codes.length > 1) {
82.280 + print(";");
82.281 + }
82.282 + }
82.283 + print("m");
82.284 + }
82.285 + }
82.286 +
82.287 + /**
82.288 + * Colors can be switched on/off during usage of this writer.
82.289 + *
82.290 + * @return whether colors are currently turned on
82.291 + * @see #isColorEnabled()
82.292 + */
82.293 + public boolean isColorful() {
82.294 + return colorful;
82.295 + }
82.296 +
82.297 + /**
82.298 + * Collors might be definitively disabled in constructor. If not, they can be turned on/off
82.299 + * during usage of this writer by {@linkplain #setColorful(boolean)}
82.300 + *
82.301 + * @return whether colors are allowed for this instance of this class
82.302 + * @see #isColorful()
82.303 + */
82.304 + public boolean isColorEnabled() {
82.305 + return COLOR_ENABLED;
82.306 + }
82.307 +
82.308 + /**
82.309 + * @see #isColorful()
82.310 + * @see #isColorEnabled()
82.311 + */
82.312 + public void setColorful(boolean colorful) {
82.313 + this.colorful = colorful;
82.314 + }
82.315 +
82.316 + public ColorfulPrintWriter(File file) throws FileNotFoundException {
82.317 + super(file);
82.318 + COLOR_ENABLED = true;
82.319 + }
82.320 +
82.321 + public ColorfulPrintWriter(OutputStream out) {
82.322 + super(out);
82.323 + COLOR_ENABLED = true;
82.324 + }
82.325 +
82.326 + public ColorfulPrintWriter(String fileName) throws FileNotFoundException {
82.327 + super(fileName);
82.328 + COLOR_ENABLED = true;
82.329 + }
82.330 +
82.331 + public ColorfulPrintWriter(Writer out) {
82.332 + super(out);
82.333 + COLOR_ENABLED = true;
82.334 + }
82.335 +
82.336 + public ColorfulPrintWriter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException {
82.337 + super(file, csn);
82.338 + COLOR_ENABLED = true;
82.339 + }
82.340 +
82.341 + /**
82.342 + * @param colorEnabled colors might be definitively disabled by this option – this might be more
82.343 + * optimalizable than dynamic turning off colors by {@linkplain #setColorful(boolean)} which is
82.344 + * not definitive (colors can be turned on during live of this instance). This might be useful
82.345 + * if you need an instance of this class but don't need colors at all.
82.346 + */
82.347 + public ColorfulPrintWriter(OutputStream out, boolean autoFlush, boolean colorEnabled) {
82.348 + super(out, autoFlush);
82.349 + COLOR_ENABLED = colorEnabled;
82.350 + }
82.351 +
82.352 + public ColorfulPrintWriter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException {
82.353 + super(fileName, csn);
82.354 + COLOR_ENABLED = true;
82.355 + }
82.356 +
82.357 + public ColorfulPrintWriter(Writer out, boolean autoFlush) {
82.358 + super(out, autoFlush);
82.359 + COLOR_ENABLED = true;
82.360 + }
82.361 +}
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
83.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/Constants.java Mon Mar 04 20:15:24 2019 +0100
83.3 @@ -0,0 +1,44 @@
83.4 +/**
83.5 + * SQL-DK
83.6 + * Copyright © 2013 František Kučera (frantovo.cz)
83.7 + *
83.8 + * This program is free software: you can redistribute it and/or modify
83.9 + * it under the terms of the GNU General Public License as published by
83.10 + * the Free Software Foundation, either version 3 of the License, or
83.11 + * (at your option) any later version.
83.12 + *
83.13 + * This program is distributed in the hope that it will be useful,
83.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
83.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83.16 + * GNU General Public License for more details.
83.17 + *
83.18 + * You should have received a copy of the GNU General Public License
83.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
83.20 + */
83.21 +package info.globalcode.sql.dk;
83.22 +
83.23 +import java.io.File;
83.24 +
83.25 +/**
83.26 + *
83.27 + * @author Ing. František Kučera (frantovo.cz)
83.28 + */
83.29 +public class Constants {
83.30 +
83.31 + public static final String PROGRAM_NAME = "SQL-DK";
83.32 + public static final String JAVA_PACKAGE = Constants.class.getPackage().getName();
83.33 + public static final String WEBSITE = "https://sql-dk.globalcode.info/";
83.34 + public static final String LICENSE_FILE = "info/globalcode/sql/dk/license.txt";
83.35 + public static final String VERSION_FILE = "info/globalcode/sql/dk/version.txt";
83.36 + public static final String HELP_FILE = "info/globalcode/sql/dk/help.txt";
83.37 + private static final File HOME_DIR = new File(System.getProperty("user.home"));
83.38 + /**
83.39 + * Directory where config and log files are stored.
83.40 + */
83.41 + public static final File DIR = new File(HOME_DIR, ".sql-dk"); // bash-completion:dir
83.42 + public static final File CONFIG_FILE = new File(DIR, "config.xml");
83.43 + public static final String EXAMPLE_CONFIG_FILE = "info/globalcode/sql/dk/example-config.xml";
83.44 +
83.45 + private Constants() {
83.46 + }
83.47 +}
84.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
84.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/DKException.java Mon Mar 04 20:15:24 2019 +0100
84.3 @@ -0,0 +1,41 @@
84.4 +/**
84.5 + * SQL-DK
84.6 + * Copyright © 2013 František Kučera (frantovo.cz)
84.7 + *
84.8 + * This program is free software: you can redistribute it and/or modify
84.9 + * it under the terms of the GNU General Public License as published by
84.10 + * the Free Software Foundation, either version 3 of the License, or
84.11 + * (at your option) any later version.
84.12 + *
84.13 + * This program is distributed in the hope that it will be useful,
84.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
84.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
84.16 + * GNU General Public License for more details.
84.17 + *
84.18 + * You should have received a copy of the GNU General Public License
84.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
84.20 + */
84.21 +package info.globalcode.sql.dk;
84.22 +
84.23 +/**
84.24 + * TODO: GEC
84.25 + *
84.26 + * @author Ing. František Kučera (frantovo.cz)
84.27 + */
84.28 +public class DKException extends Exception {
84.29 +
84.30 + public DKException() {
84.31 + }
84.32 +
84.33 + public DKException(String message) {
84.34 + super(message);
84.35 + }
84.36 +
84.37 + public DKException(Throwable cause) {
84.38 + super(cause);
84.39 + }
84.40 +
84.41 + public DKException(String message, Throwable cause) {
84.42 + super(message, cause);
84.43 + }
84.44 +}
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
85.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/DatabaseConnection.java Mon Mar 04 20:15:24 2019 +0100
85.3 @@ -0,0 +1,192 @@
85.4 +/**
85.5 + * SQL-DK
85.6 + * Copyright © 2013 František Kučera (frantovo.cz)
85.7 + *
85.8 + * This program is free software: you can redistribute it and/or modify
85.9 + * it under the terms of the GNU General Public License as published by
85.10 + * the Free Software Foundation, either version 3 of the License, or
85.11 + * (at your option) any later version.
85.12 + *
85.13 + * This program is distributed in the hope that it will be useful,
85.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
85.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85.16 + * GNU General Public License for more details.
85.17 + *
85.18 + * You should have received a copy of the GNU General Public License
85.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
85.20 + */
85.21 +package info.globalcode.sql.dk;
85.22 +
85.23 +import static info.globalcode.sql.dk.jmx.ConnectionManagement.incrementCounter;
85.24 +import static info.globalcode.sql.dk.jmx.ConnectionManagement.resetCounter;
85.25 +import info.globalcode.sql.dk.batch.Batch;
85.26 +import info.globalcode.sql.dk.batch.BatchException;
85.27 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
85.28 +import info.globalcode.sql.dk.configuration.Loader;
85.29 +import info.globalcode.sql.dk.configuration.Properties;
85.30 +import info.globalcode.sql.dk.formatting.ColumnsHeader;
85.31 +import info.globalcode.sql.dk.formatting.Formatter;
85.32 +import info.globalcode.sql.dk.jmx.ConnectionManagement;
85.33 +import info.globalcode.sql.dk.jmx.ConnectionManagement.COUNTER;
85.34 +import java.sql.Connection;
85.35 +import java.sql.PreparedStatement;
85.36 +import java.sql.ResultSet;
85.37 +import java.sql.SQLException;
85.38 +import java.sql.SQLWarning;
85.39 +import java.util.logging.Level;
85.40 +import java.util.logging.Logger;
85.41 +
85.42 +/**
85.43 + * Represents connected database. Is derived from {@linkplain DatabaseDefinition}.
85.44 + * Wraps {@linkplain Connection}.
85.45 + *
85.46 + * Is responsible for executing {@linkplain SQLCommand} and passing results to the
85.47 + * {@linkplain Formatter}.
85.48 + *
85.49 + * @author Ing. František Kučera (frantovo.cz)
85.50 + */
85.51 +public class DatabaseConnection implements AutoCloseable {
85.52 +
85.53 + private static final Logger log = Logger.getLogger(DatabaseConnection.class.getName());
85.54 + public static final String JDBC_PROPERTY_USER = "user";
85.55 + public static final String JDBC_PROPERTY_PASSWORD = "password";
85.56 + private final DatabaseDefinition databaseDefinition;
85.57 + private final Connection connection;
85.58 + private final Properties properties;
85.59 + /**
85.60 + * Could be null = JMX is disabled → must check, see functions in
85.61 + * {@linkplain ConnectionManagement}
85.62 + */
85.63 + private final ConnectionManagement connectionMBean;
85.64 +
85.65 + /**
85.66 + *
85.67 + * @param databaseDefinition DB url, name, password etc.
85.68 + * @param properties additional properties from CLI
85.69 + * @param connectionMBean JMX management bean | null = disabled JMX reporting
85.70 + * @throws SQLException
85.71 + */
85.72 + public DatabaseConnection(DatabaseDefinition databaseDefinition, Properties properties, ConnectionManagement connectionMBean) throws SQLException {
85.73 + this.databaseDefinition = databaseDefinition;
85.74 + this.properties = properties;
85.75 + this.connectionMBean = connectionMBean;
85.76 + this.connection = Loader.jdbcConnect(databaseDefinition, properties);
85.77 + }
85.78 +
85.79 + public void executeQuery(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
85.80 + formatter.writeStartBatch();
85.81 + formatter.writeStartDatabase(databaseDefinition);
85.82 + formatter.writeStartStatement();
85.83 + formatter.writeQuery(sqlCommand.getQuery());
85.84 + formatter.writeParameters(sqlCommand.getParameters());
85.85 + processCommand(sqlCommand, formatter);
85.86 + formatter.writeEndStatement();
85.87 + formatter.writeEndDatabase();
85.88 + formatter.writeEndBatch();
85.89 + }
85.90 +
85.91 + public void executeBatch(Batch batch, Formatter formatter) throws SQLException, BatchException {
85.92 + formatter.writeStartBatch();
85.93 + formatter.writeStartDatabase(databaseDefinition);
85.94 + while (batch.hasNext()) {
85.95 + SQLCommand sqlCommand = batch.next();
85.96 + formatter.writeStartStatement();
85.97 + formatter.writeQuery(sqlCommand.getQuery());
85.98 + formatter.writeParameters(sqlCommand.getParameters());
85.99 + processCommand(sqlCommand, formatter);
85.100 + formatter.writeEndStatement();
85.101 + }
85.102 + formatter.writeEndDatabase();
85.103 + formatter.writeEndBatch();
85.104 + }
85.105 +
85.106 + private void processCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
85.107 + incrementCounter(connectionMBean, COUNTER.COMMAND);
85.108 + resetCounter(connectionMBean, COUNTER.RECORD_CURRENT);
85.109 +
85.110 + try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) {
85.111 + log.log(Level.FINE, "Statement prepared");
85.112 + sqlCommand.parametrize(ps);
85.113 +
85.114 + boolean isRS = ps.execute();
85.115 + log.log(Level.FINE, "Statement executed");
85.116 + if (isRS) {
85.117 + try (ResultSet rs = ps.getResultSet()) {
85.118 + processResultSet(rs, formatter);
85.119 + }
85.120 + } else {
85.121 + processUpdateResult(ps, formatter);
85.122 + }
85.123 + logWarnings(ps);
85.124 +
85.125 + while (ps.getMoreResults() || ps.getUpdateCount() > -1) {
85.126 + ResultSet rs = ps.getResultSet();
85.127 + if (rs == null) {
85.128 + processUpdateResult(ps, formatter);
85.129 + } else {
85.130 + processResultSet(rs, formatter);
85.131 + rs.close();
85.132 + }
85.133 + logWarnings(ps);
85.134 + }
85.135 + }
85.136 + }
85.137 +
85.138 + private void processUpdateResult(PreparedStatement ps, Formatter formatter) throws SQLException {
85.139 + formatter.writeUpdatesResult(ps.getUpdateCount());
85.140 + }
85.141 +
85.142 + private void processResultSet(ResultSet rs, Formatter formatter) throws SQLException {
85.143 + formatter.writeStartResultSet(new ColumnsHeader(rs.getMetaData()));
85.144 +
85.145 + int columnCount = rs.getMetaData().getColumnCount();
85.146 +
85.147 + while (rs.next()) {
85.148 + incrementCounter(connectionMBean, COUNTER.RECORD_CURRENT);
85.149 + incrementCounter(connectionMBean, COUNTER.RECORD_TOTAL);
85.150 +
85.151 + formatter.writeStartRow();
85.152 +
85.153 + for (int i = 1; i <= columnCount; i++) {
85.154 + formatter.writeColumnValue(rs.getObject(i));
85.155 + }
85.156 +
85.157 + formatter.writeEndRow();
85.158 + }
85.159 +
85.160 + formatter.writeEndResultSet();
85.161 + }
85.162 +
85.163 + private void logWarnings(PreparedStatement ps) throws SQLException {
85.164 + SQLWarning w = ps.getWarnings();
85.165 + while (w != null) {
85.166 + log.log(Level.WARNING, "SQL: {0}", w.getLocalizedMessage());
85.167 + w = w.getNextWarning();
85.168 + }
85.169 + ps.clearWarnings();
85.170 + }
85.171 +
85.172 + /**
85.173 + * Tests if this connection is live.
85.174 + *
85.175 + * @return true if test was successful
85.176 + * @throws SQLException if test fails
85.177 + */
85.178 + public boolean test() throws SQLException {
85.179 + connection.getAutoCommit();
85.180 + return true;
85.181 + }
85.182 +
85.183 + public String getProductName() throws SQLException {
85.184 + return connection.getMetaData().getDatabaseProductName();
85.185 + }
85.186 +
85.187 + public String getProductVersion() throws SQLException {
85.188 + return connection.getMetaData().getDatabaseProductVersion();
85.189 + }
85.190 +
85.191 + @Override
85.192 + public void close() throws SQLException {
85.193 + connection.close();
85.194 + }
85.195 +}
86.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
86.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/Functions.java Mon Mar 04 20:15:24 2019 +0100
86.3 @@ -0,0 +1,254 @@
86.4 +/**
86.5 + * SQL-DK
86.6 + * Copyright © 2013 František Kučera (frantovo.cz)
86.7 + *
86.8 + * This program is free software: you can redistribute it and/or modify
86.9 + * it under the terms of the GNU General Public License as published by
86.10 + * the Free Software Foundation, either version 3 of the License, or
86.11 + * (at your option) any later version.
86.12 + *
86.13 + * This program is distributed in the hope that it will be useful,
86.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
86.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86.16 + * GNU General Public License for more details.
86.17 + *
86.18 + * You should have received a copy of the GNU General Public License
86.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
86.20 + */
86.21 +package info.globalcode.sql.dk;
86.22 +
86.23 +import info.globalcode.sql.dk.configuration.NameIdentified;
86.24 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
86.25 +import info.globalcode.sql.dk.configuration.PropertyDeclarations;
86.26 +import info.globalcode.sql.dk.formatting.Formatter;
86.27 +import java.io.BufferedReader;
86.28 +import java.io.File;
86.29 +import java.io.IOException;
86.30 +import java.io.InputStream;
86.31 +import java.io.InputStreamReader;
86.32 +import java.io.PrintWriter;
86.33 +import java.util.ArrayList;
86.34 +import java.util.Arrays;
86.35 +import java.util.Collection;
86.36 +import java.util.Collections;
86.37 +import java.util.List;
86.38 +import java.util.Map;
86.39 +import java.util.regex.Matcher;
86.40 +import java.util.regex.Pattern;
86.41 +
86.42 +/**
86.43 + *
86.44 + * @author Ing. František Kučera (frantovo.cz)
86.45 + */
86.46 +public class Functions {
86.47 +
86.48 + private static final String NBSP = " ";
86.49 + private static final Pattern WHITESPACE_TO_REPLACE = Pattern.compile("\\n|\\r|\\t|" + NBSP);
86.50 +
86.51 + private Functions() {
86.52 + }
86.53 +
86.54 + public static boolean equalz(Object a, Object b) {
86.55 + return a == null ? b == null : a.equals(b);
86.56 + }
86.57 +
86.58 + /**
86.59 + *
86.60 + * @param text String to be examinated
86.61 + * @param trim whether text should be trimmed before examination
86.62 + * @return whether text is not empty and one or more characters long (after prospective trim)
86.63 + */
86.64 + public static boolean isEmpty(String text, boolean trim) {
86.65 + if (text == null) {
86.66 + return true;
86.67 + } else {
86.68 + if (trim) {
86.69 + text = text.trim();
86.70 + }
86.71 + return text.isEmpty();
86.72 + }
86.73 + }
86.74 +
86.75 + /**
86.76 + * @see #isEmpty(java.lang.String, boolean)
86.77 + */
86.78 + public static boolean isNotEmpty(String text, boolean trim) {
86.79 + return !isEmpty(text, trim);
86.80 + }
86.81 +
86.82 + public boolean isEmpty(Collection c) {
86.83 + return c == null || c.isEmpty();
86.84 + }
86.85 +
86.86 + public boolean isNotEmpty(Collection c) {
86.87 + return !isEmpty(c);
86.88 + }
86.89 +
86.90 + public boolean isEmpty(Map m) {
86.91 + return m == null || m.isEmpty();
86.92 + }
86.93 +
86.94 + public boolean isNotEmpty(Map m) {
86.95 + return !isEmpty(m);
86.96 + }
86.97 +
86.98 + /**
86.99 + * @return empty collection if given one is null | or the original one
86.100 + */
86.101 + public static <T> Collection<T> notNull(Collection<T> c) {
86.102 + if (c == null) {
86.103 + return Collections.emptyList();
86.104 + } else {
86.105 + return c;
86.106 + }
86.107 + }
86.108 +
86.109 + public static <T extends NameIdentified> T findByName(Collection<T> collection, String name) {
86.110 + for (T element : notNull(collection)) {
86.111 + if (element != null && equalz(element.getName(), name)) {
86.112 + return element;
86.113 + }
86.114 + }
86.115 +
86.116 + return null;
86.117 + }
86.118 +
86.119 + /**
86.120 + * Copy file from Java resources to file system.
86.121 + */
86.122 + public static void installResource(String resourceName, File target) throws IOException {
86.123 + try (BufferedReader reader = new BufferedReader(new InputStreamReader(Functions.class.getClassLoader().getResourceAsStream(resourceName)))) {
86.124 + try (PrintWriter writer = new PrintWriter(target)) {
86.125 + while (true) {
86.126 + String line = reader.readLine();
86.127 + if (line == null) {
86.128 + break;
86.129 + } else {
86.130 + writer.println(line);
86.131 + }
86.132 + }
86.133 + }
86.134 + }
86.135 + }
86.136 +
86.137 + public static String rpad(String s, int n) {
86.138 + if (n > 0) {
86.139 + return String.format("%1$-" + n + "s", s);
86.140 + } else {
86.141 + return s;
86.142 + }
86.143 + }
86.144 +
86.145 + public static String lpad(String s, int n) {
86.146 + if (n > 0) {
86.147 + return String.format("%1$" + n + "s", s);
86.148 + } else {
86.149 + return s;
86.150 + }
86.151 + }
86.152 +
86.153 + public static String repeat(char ch, int count) {
86.154 + char[] array = new char[count];
86.155 + Arrays.fill(array, ch);
86.156 + return new String(array);
86.157 + }
86.158 + private final static char[] HEX_ALPHABET = "0123456789abcdef".toCharArray();
86.159 +
86.160 + public static String toHex(byte[] bytes) {
86.161 + char[] hexChars = new char[bytes.length * 2];
86.162 + for (int j = 0; j < bytes.length; j++) {
86.163 + int v = bytes[j] & 0xFF;
86.164 + hexChars[j * 2] = HEX_ALPHABET[v >>> 4];
86.165 + hexChars[j * 2 + 1] = HEX_ALPHABET[v & 0x0F];
86.166 + }
86.167 + return new String(hexChars);
86.168 + }
86.169 +
86.170 + public static String readString(InputStream in) throws IOException {
86.171 + try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
86.172 + StringBuilder result = new StringBuilder();
86.173 + for (String line = br.readLine(); line != null; line = br.readLine()) {
86.174 + result.append(line);
86.175 + result.append('\n');
86.176 + }
86.177 + return result.toString();
86.178 + }
86.179 + }
86.180 +
86.181 + /**
86.182 + * @param <P> type of the last parent
86.183 + * @param <T> type of the examined class
86.184 + * @param type examined class
86.185 + * @param lastParent the last parent type to stop at
86.186 + * @return list of types starting with <code>type</code> and ending with <code>lastParent</code>
86.187 + */
86.188 + public static <P, T extends P> List<Class<? extends P>> getClassHierarchy(Class<T> type, Class<P> lastParent) {
86.189 + List<Class<? extends P>> hierarchy = new ArrayList<>();
86.190 +
86.191 + for (Class current = type; current != null && lastParent.isAssignableFrom(current); current = current.getSuperclass()) {
86.192 + hierarchy.add(current);
86.193 + }
86.194 +
86.195 + return hierarchy;
86.196 + }
86.197 +
86.198 + public static PropertyDeclaration[] getPropertyDeclarations(Class<? extends Formatter> formatterClass) {
86.199 + PropertyDeclarations properties = formatterClass.getAnnotation(PropertyDeclarations.class);
86.200 +
86.201 + if (properties == null) {
86.202 + PropertyDeclaration p = formatterClass.getAnnotation(PropertyDeclaration.class);
86.203 + return p == null ? new PropertyDeclaration[]{} : new PropertyDeclaration[]{p};
86.204 + } else {
86.205 + return properties.value();
86.206 + }
86.207 + }
86.208 +
86.209 + /**
86.210 + * TODO: support background or styles and move to ColorfulPrintWriter
86.211 + *
86.212 + * @param out
86.213 + * @param valueString
86.214 + * @param basicColor
86.215 + * @param escapeColor
86.216 + */
86.217 + public static void printValueWithWhitespaceReplaced(ColorfulPrintWriter out, String valueString, ColorfulPrintWriter.TerminalColor basicColor, ColorfulPrintWriter.TerminalColor escapeColor) {
86.218 +
86.219 + Matcher m = WHITESPACE_TO_REPLACE.matcher(valueString);
86.220 +
86.221 + int start = 0;
86.222 +
86.223 + while (m.find(start)) {
86.224 +
86.225 + printColorOrNot(out, basicColor, valueString.substring(start, m.start()));
86.226 +
86.227 + switch (m.group()) {
86.228 + case "\n":
86.229 + out.print(escapeColor, "↲");
86.230 + break;
86.231 + case "\r":
86.232 + out.print(escapeColor, "⏎");
86.233 + break;
86.234 + case "\t":
86.235 + out.print(escapeColor, "↹");
86.236 + break;
86.237 + case NBSP:
86.238 + out.print(escapeColor, "⎵");
86.239 + break;
86.240 + default:
86.241 + throw new IllegalStateException("Unexpected whitespace token: „" + m.group() + "“");
86.242 + }
86.243 +
86.244 + start = m.end();
86.245 + }
86.246 +
86.247 + printColorOrNot(out, basicColor, valueString.substring(start, valueString.length()));
86.248 + }
86.249 +
86.250 + private static void printColorOrNot(ColorfulPrintWriter out, ColorfulPrintWriter.TerminalColor color, String text) {
86.251 + if (color == null) {
86.252 + out.print(text);
86.253 + } else {
86.254 + out.print(color, text);
86.255 + }
86.256 + }
86.257 +}
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/InfoLister.java Mon Mar 04 20:15:24 2019 +0100
87.3 @@ -0,0 +1,673 @@
87.4 +/**
87.5 + * SQL-DK
87.6 + * Copyright © 2013 František Kučera (frantovo.cz)
87.7 + *
87.8 + * This program is free software: you can redistribute it and/or modify
87.9 + * it under the terms of the GNU General Public License as published by
87.10 + * the Free Software Foundation, either version 3 of the License, or
87.11 + * (at your option) any later version.
87.12 + *
87.13 + * This program is distributed in the hope that it will be useful,
87.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
87.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
87.16 + * GNU General Public License for more details.
87.17 + *
87.18 + * You should have received a copy of the GNU General Public License
87.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
87.20 + */
87.21 +package info.globalcode.sql.dk;
87.22 +
87.23 +import info.globalcode.sql.dk.configuration.CommandArgument;
87.24 +import info.globalcode.sql.dk.configuration.Configuration;
87.25 +import info.globalcode.sql.dk.configuration.ConfigurationException;
87.26 +import info.globalcode.sql.dk.configuration.ConfigurationProvider;
87.27 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
87.28 +import info.globalcode.sql.dk.configuration.FormatterDefinition;
87.29 +import info.globalcode.sql.dk.configuration.Properties;
87.30 +import info.globalcode.sql.dk.configuration.Property;
87.31 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
87.32 +import info.globalcode.sql.dk.configuration.TunnelDefinition;
87.33 +import info.globalcode.sql.dk.formatting.ColumnsHeader;
87.34 +import info.globalcode.sql.dk.formatting.CommonProperties;
87.35 +import info.globalcode.sql.dk.formatting.FakeSqlArray;
87.36 +import info.globalcode.sql.dk.formatting.Formatter;
87.37 +import info.globalcode.sql.dk.formatting.FormatterContext;
87.38 +import info.globalcode.sql.dk.formatting.FormatterException;
87.39 +import java.io.BufferedReader;
87.40 +import java.io.ByteArrayOutputStream;
87.41 +import java.io.InputStreamReader;
87.42 +import java.io.PrintStream;
87.43 +import java.sql.Array;
87.44 +import java.sql.Driver;
87.45 +import java.sql.DriverManager;
87.46 +import java.sql.DriverPropertyInfo;
87.47 +import java.sql.SQLException;
87.48 +import java.util.ArrayList;
87.49 +import java.util.Collections;
87.50 +import java.util.Comparator;
87.51 +import java.util.EnumSet;
87.52 +import java.util.HashMap;
87.53 +import java.util.HashSet;
87.54 +import java.util.List;
87.55 +import java.util.Map;
87.56 +import java.util.Map.Entry;
87.57 +import java.util.ServiceLoader;
87.58 +import java.util.Set;
87.59 +import java.util.concurrent.ExecutorService;
87.60 +import java.util.concurrent.Executors;
87.61 +import java.util.concurrent.TimeUnit;
87.62 +import java.util.logging.Level;
87.63 +import java.util.logging.LogRecord;
87.64 +import java.util.logging.Logger;
87.65 +import javax.sql.rowset.RowSetMetaDataImpl;
87.66 +
87.67 +/**
87.68 + * Displays info like help, version etc.
87.69 + *
87.70 + * @author Ing. František Kučera (frantovo.cz)
87.71 + */
87.72 +public class InfoLister {
87.73 +
87.74 + private static final Logger log = Logger.getLogger(InfoLister.class.getName());
87.75 + /**
87.76 + * Fake database name for output formatting
87.77 + */
87.78 + public static final String CONFIG_DB_NAME = "sqldk_configuration";
87.79 + private final PrintStream out;
87.80 + private final ConfigurationProvider configurationProvider;
87.81 + private final CLIOptions options;
87.82 + private Formatter formatter;
87.83 +
87.84 + public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
87.85 + this.out = out;
87.86 + this.configurationProvider = configurationProvider;
87.87 + this.options = options;
87.88 + }
87.89 +
87.90 + public void showInfo() throws ConfigurationException, FormatterException {
87.91 + EnumSet<InfoType> commands = options.getShowInfo();
87.92 +
87.93 + boolean formattinNeeded = false;
87.94 +
87.95 + for (InfoType infoType : commands) {
87.96 + switch (infoType) {
87.97 + case CONNECTION:
87.98 + case JDBC_DRIVERS:
87.99 + case JDBC_PROPERTIES:
87.100 + case DATABASES:
87.101 + case FORMATTERS:
87.102 + case FORMATTER_PROPERTIES:
87.103 + case TYPES:
87.104 + case JAVA_PROPERTIES:
87.105 + case ENVIRONMENT_VARIABLES:
87.106 + formattinNeeded = true;
87.107 + break;
87.108 + }
87.109 + }
87.110 +
87.111 + if (formattinNeeded) {
87.112 + try (Formatter f = getFormatter()) {
87.113 + formatter = f;
87.114 + formatter.writeStartBatch();
87.115 + DatabaseDefinition dd = new DatabaseDefinition();
87.116 + dd.setName(CONFIG_DB_NAME);
87.117 + formatter.writeStartDatabase(dd);
87.118 + showInfos(commands);
87.119 + formatter.writeEndDatabase();
87.120 + formatter.writeEndBatch();
87.121 + formatter.close();
87.122 + }
87.123 + } else {
87.124 + showInfos(commands);
87.125 + }
87.126 + }
87.127 +
87.128 + private void showInfos(EnumSet<InfoType> commands) throws ConfigurationException, FormatterException {
87.129 + for (InfoType infoType : commands) {
87.130 + infoType.showInfo(this);
87.131 + }
87.132 + }
87.133 +
87.134 + private void listJavaProperties() throws FormatterException, ConfigurationException {
87.135 + ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
87.136 + List<Object[]> data = new ArrayList<>();
87.137 + for (Entry<Object, Object> e : System.getProperties().entrySet()) {
87.138 + data.add(new Object[]{e.getKey(), e.getValue()});
87.139 + }
87.140 + printTable(formatter, header, "-- Java system properties", null, data, 0);
87.141 + }
87.142 +
87.143 + private void listEnvironmentVariables() throws FormatterException, ConfigurationException {
87.144 + ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("value", SQLType.VARCHAR));
87.145 + List<Object[]> data = new ArrayList<>();
87.146 + for (Entry<String, String> e : System.getenv().entrySet()) {
87.147 + data.add(new Object[]{e.getKey(), e.getValue()});
87.148 + }
87.149 + printTable(formatter, header, "-- environment variables", null, data, 0);
87.150 + }
87.151 +
87.152 + private void listFormatters() throws ConfigurationException, FormatterException {
87.153 + ColumnsHeader header = constructHeader(
87.154 + new HeaderField("name", SQLType.VARCHAR),
87.155 + new HeaderField("built_in", SQLType.BOOLEAN),
87.156 + new HeaderField("default", SQLType.BOOLEAN),
87.157 + new HeaderField("class_name", SQLType.VARCHAR),
87.158 + new HeaderField("valid", SQLType.BOOLEAN));
87.159 + List<Object[]> data = new ArrayList<>();
87.160 +
87.161 + String defaultFormatter = configurationProvider.getConfiguration().getDefaultFormatter();
87.162 + defaultFormatter = defaultFormatter == null ? Configuration.DEFAULT_FORMATTER : defaultFormatter;
87.163 +
87.164 + for (FormatterDefinition fd : configurationProvider.getConfiguration().getBuildInFormatters()) {
87.165 + data.add(new Object[]{fd.getName(), true, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
87.166 + }
87.167 +
87.168 + for (FormatterDefinition fd : configurationProvider.getConfiguration().getFormatters()) {
87.169 + data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
87.170 + }
87.171 +
87.172 + printTable(formatter, header, "-- configured and built-in output formatters", null, data);
87.173 + }
87.174 +
87.175 + private boolean isInstantiable(FormatterDefinition fd) {
87.176 + try {
87.177 + try (ByteArrayOutputStream testStream = new ByteArrayOutputStream()) {
87.178 + fd.getInstance(new FormatterContext(testStream, new Properties(0)));
87.179 + return true;
87.180 + }
87.181 + } catch (Exception e) {
87.182 + log.log(Level.SEVERE, "Unable to create an instance of formatter: " + fd.getName(), e);
87.183 + return false;
87.184 + }
87.185 + }
87.186 +
87.187 + private void listFormatterProperties() throws FormatterException, ConfigurationException {
87.188 + for (String formatterName : options.getFormatterNamesToListProperties()) {
87.189 + listFormatterProperties(formatterName);
87.190 + }
87.191 + }
87.192 +
87.193 + private void listFormatterProperties(String formatterName) throws FormatterException, ConfigurationException {
87.194 + FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
87.195 + try {
87.196 +
87.197 + // currently only for debugging purposes
87.198 + // TODO: introduce --info-lister-property or generic filtering capability in printTable() ?
87.199 + boolean printDeclaredIn = options.getFormatterProperties().getBoolean("InfoLister:print:declared_in", false);
87.200 +
87.201 + List<HeaderField> headerFields = new ArrayList<>();
87.202 + headerFields.add(new HeaderField("name", SQLType.VARCHAR));
87.203 + headerFields.add(new HeaderField("type", SQLType.VARCHAR));
87.204 + headerFields.add(new HeaderField("default", SQLType.VARCHAR));
87.205 + headerFields.add(new HeaderField("description", SQLType.VARCHAR));
87.206 + if (printDeclaredIn) {
87.207 + headerFields.add(new HeaderField("declared_in", SQLType.VARCHAR));
87.208 + }
87.209 +
87.210 + ColumnsHeader header = constructHeader(headerFields.toArray(new HeaderField[0]));
87.211 +
87.212 + Map<String, Object[]> data = new HashMap<>();
87.213 + Class<Formatter> formatterClass = (Class<Formatter>) Class.forName(fd.getClassName());
87.214 + List<Class<? extends Formatter>> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class);
87.215 + Collections.reverse(hierarchy);
87.216 + hierarchy.stream().forEach((c) -> {
87.217 + for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) {
87.218 + data.put(p.name(), propertyDeclarationToRow(p, c, printDeclaredIn));
87.219 + }
87.220 + });
87.221 +
87.222 + List<Parameter> parameters = new ArrayList<>();
87.223 + parameters.add(new NamedParameter("formatter", formatterName, SQLType.VARCHAR));
87.224 +
87.225 + printTable(formatter, header, "-- formatter properties", parameters, new ArrayList<>(data.values()));
87.226 + } catch (ClassNotFoundException e) {
87.227 + throw new ConfigurationException("Unable to find class " + fd.getClassName() + " of formatter" + fd.getName(), e);
87.228 + }
87.229 + }
87.230 +
87.231 + private static Object[] propertyDeclarationToRow(PropertyDeclaration p, Class formatterClass, boolean printDeclaredIn) {
87.232 + List list = new ArrayList();
87.233 +
87.234 + list.add(p.name());
87.235 + list.add(CommonProperties.getSimpleTypeName(p.type()));
87.236 + list.add(p.defaultValue());
87.237 + list.add(p.description());
87.238 + if (printDeclaredIn) {
87.239 + list.add(formatterClass.getName());
87.240 + }
87.241 +
87.242 + return list.toArray();
87.243 + }
87.244 +
87.245 + private void listTypes() throws FormatterException, ConfigurationException {
87.246 + ColumnsHeader header = constructHeader(new HeaderField("name", SQLType.VARCHAR), new HeaderField("code", SQLType.INTEGER));
87.247 + List<Object[]> data = new ArrayList<>();
87.248 + for (SQLType sqlType : SQLType.values()) {
87.249 + data.add(new Object[]{sqlType.name(), sqlType.getCode()});
87.250 + }
87.251 + printTable(formatter, header, "-- data types", null, data);
87.252 + log.log(Level.INFO, "Type names in --types option are case insensitive");
87.253 + }
87.254 +
87.255 + private void listDatabases() throws ConfigurationException, FormatterException {
87.256 + ColumnsHeader header = constructHeader(
87.257 + new HeaderField("database_name", SQLType.VARCHAR),
87.258 + new HeaderField("user_name", SQLType.VARCHAR),
87.259 + new HeaderField("database_url", SQLType.VARCHAR));
87.260 + List<Object[]> data = new ArrayList<>();
87.261 +
87.262 + final List<DatabaseDefinition> configuredDatabases = configurationProvider.getConfiguration().getDatabases();
87.263 + if (configuredDatabases.isEmpty()) {
87.264 + log.log(Level.WARNING, "No databases are configured.");
87.265 + } else {
87.266 + for (DatabaseDefinition dd : configuredDatabases) {
87.267 + data.add(new Object[]{dd.getName(), dd.getUserName(), dd.getUrl()});
87.268 +
87.269 + final TunnelDefinition tunnel = dd.getTunnel();
87.270 + if (tunnel != null) {
87.271 + log.log(Level.INFO, "Tunnel command: {0}", tunnel.getCommand());
87.272 + for (CommandArgument ca : Functions.notNull(tunnel.getArguments())) {
87.273 + log.log(Level.INFO, "\targument: {0}/{1}", new Object[]{ca.getType(), ca.getValue()});
87.274 + }
87.275 + }
87.276 +
87.277 + }
87.278 + }
87.279 +
87.280 + printTable(formatter, header, "-- configured databases", null, data);
87.281 + }
87.282 +
87.283 + private void listJdbcDrivers() throws FormatterException, ConfigurationException {
87.284 + ColumnsHeader header = constructHeader(
87.285 + new HeaderField("class", SQLType.VARCHAR),
87.286 + new HeaderField("version", SQLType.VARCHAR),
87.287 + new HeaderField("major", SQLType.INTEGER),
87.288 + new HeaderField("minor", SQLType.INTEGER),
87.289 + new HeaderField("jdbc_compliant", SQLType.BOOLEAN));
87.290 + List<Object[]> data = new ArrayList<>();
87.291 +
87.292 + final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
87.293 + for (Driver d : drivers) {
87.294 + data.add(new Object[]{
87.295 + d.getClass().getName(),
87.296 + d.getMajorVersion() + "." + d.getMinorVersion(),
87.297 + d.getMajorVersion(),
87.298 + d.getMinorVersion(),
87.299 + d.jdbcCompliant()
87.300 + });
87.301 + }
87.302 +
87.303 + printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
87.304 + }
87.305 +
87.306 + private void listJdbcProperties() throws FormatterException, ConfigurationException {
87.307 + for (String dbName : options.getDatabaseNamesToListProperties()) {
87.308 + ColumnsHeader header = constructHeader(
87.309 + new HeaderField("property_name", SQLType.VARCHAR),
87.310 + new HeaderField("required", SQLType.BOOLEAN),
87.311 + new HeaderField("choices", SQLType.ARRAY),
87.312 + new HeaderField("configured_value", SQLType.VARCHAR),
87.313 + new HeaderField("description", SQLType.VARCHAR));
87.314 + List<Object[]> data = new ArrayList<>();
87.315 +
87.316 + DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
87.317 +
87.318 + Driver driver = findDriver(dd);
87.319 +
87.320 + if (driver == null) {
87.321 + log.log(Level.WARNING, "No JDBC driver was found for DB: {0} with URL: {1}", new Object[]{dd.getName(), dd.getUrl()});
87.322 + } else {
87.323 + log.log(Level.INFO, "For DB: {0} was found JDBC driver: {1}", new Object[]{dd.getName(), driver.getClass().getName()});
87.324 +
87.325 + try {
87.326 + DriverPropertyInfo[] propertyInfos = driver.getPropertyInfo(dd.getUrl(), dd.getProperties().getJavaProperties());
87.327 +
87.328 + Set<String> standardProperties = new HashSet<>();
87.329 +
87.330 + for (DriverPropertyInfo pi : propertyInfos) {
87.331 + Array choices = new FakeSqlArray(pi.choices, SQLType.VARCHAR);
87.332 + data.add(new Object[]{
87.333 + pi.name,
87.334 + pi.required,
87.335 + choices.getArray() == null ? "" : choices,
87.336 + pi.value == null ? "" : pi.value,
87.337 + pi.description
87.338 + });
87.339 + standardProperties.add(pi.name);
87.340 + }
87.341 +
87.342 + for (Property p : dd.getProperties()) {
87.343 + if (!standardProperties.contains(p.getName())) {
87.344 + data.add(new Object[]{
87.345 + p.getName(),
87.346 + "",
87.347 + "",
87.348 + p.getValue(),
87.349 + ""
87.350 + });
87.351 + log.log(Level.WARNING, "Your configuration contains property „{0}“ not declared by the JDBC driver.", p.getName());
87.352 + }
87.353 + }
87.354 +
87.355 + } catch (SQLException e) {
87.356 + log.log(Level.WARNING, "Error during getting property infos.", e);
87.357 + }
87.358 +
87.359 + List<Parameter> parameters = new ArrayList<>();
87.360 + parameters.add(new NamedParameter("database", dbName, SQLType.VARCHAR));
87.361 + parameters.add(new NamedParameter("driver_class", driver.getClass().getName(), SQLType.VARCHAR));
87.362 + parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
87.363 + parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
87.364 +
87.365 + printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
87.366 + }
87.367 + }
87.368 +
87.369 + }
87.370 +
87.371 + private Driver findDriver(DatabaseDefinition dd) {
87.372 + final ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
87.373 + for (Driver d : drivers) {
87.374 + try {
87.375 + if (d.acceptsURL(dd.getUrl())) {
87.376 + return d;
87.377 + }
87.378 + } catch (SQLException e) {
87.379 + log.log(Level.WARNING, "Error during finding JDBC driver for: " + dd.getName(), e);
87.380 + }
87.381 + }
87.382 + return null;
87.383 + }
87.384 +
87.385 + /**
87.386 + * Parallelism for connection testing – maximum concurrent database connections.
87.387 + */
87.388 + private static final int TESTING_THREAD_COUNT = 64;
87.389 + /**
87.390 + * Time limit for all connection testing threads – particular timeouts per connection will be
87.391 + * much smaller.
87.392 + */
87.393 + private static final long TESTING_AWAIT_LIMIT = 1;
87.394 + private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
87.395 +
87.396 + private void testConnections() throws FormatterException, ConfigurationException {
87.397 + ColumnsHeader header = constructHeader(
87.398 + new HeaderField("database_name", SQLType.VARCHAR),
87.399 + new HeaderField("configured", SQLType.BOOLEAN),
87.400 + new HeaderField("connected", SQLType.BOOLEAN),
87.401 + new HeaderField("product_name", SQLType.VARCHAR),
87.402 + new HeaderField("product_version", SQLType.VARCHAR));
87.403 +
87.404 + log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
87.405 +
87.406 + ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
87.407 +
87.408 + final Formatter currentFormatter = formatter;
87.409 +
87.410 + printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
87.411 +
87.412 + for (final String dbName : options.getDatabaseNamesToTest()) {
87.413 + preloadDriver(dbName);
87.414 + }
87.415 +
87.416 + for (final String dbName : options.getDatabaseNamesToTest()) {
87.417 + es.submit(() -> {
87.418 + final Object[] row = testConnection(dbName);
87.419 + synchronized (currentFormatter) {
87.420 + printRow(currentFormatter, row);
87.421 + }
87.422 + }
87.423 + );
87.424 + }
87.425 +
87.426 + es.shutdown();
87.427 +
87.428 + try {
87.429 + log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
87.430 + boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
87.431 + if (finished) {
87.432 + log.log(Level.FINEST, "All testing threads finished in time limit.");
87.433 + } else {
87.434 + throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
87.435 + }
87.436 + } catch (InterruptedException e) {
87.437 + throw new FormatterException("Interrupted while waiting for test results", e);
87.438 + }
87.439 +
87.440 + printFooter(currentFormatter);
87.441 + }
87.442 +
87.443 + /**
87.444 + * JDBC driver classes should be preloaded in single thread to avoid deadlocks while doing
87.445 + * {@linkplain DriverManager#registerDriver(java.sql.Driver)} during parallel connections.
87.446 + *
87.447 + * @param dbName
87.448 + */
87.449 + private void preloadDriver(String dbName) {
87.450 + try {
87.451 + DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
87.452 + Driver driver = findDriver(dd);
87.453 + if (driver == null) {
87.454 + log.log(Level.WARNING, "No Driver found for DB: {0}", dbName);
87.455 + } else {
87.456 + log.log(Level.FINEST, "Driver preloading for DB: {0} was successfull", dbName);
87.457 + }
87.458 + } catch (Exception e) {
87.459 + LogRecord r = new LogRecord(Level.WARNING, "Failed to preload the Driver for DB: {0}");
87.460 + r.setParameters(new Object[]{dbName});
87.461 + r.setThrown(e);
87.462 + log.log(r);
87.463 + }
87.464 + }
87.465 +
87.466 + private Object[] testConnection(String dbName) {
87.467 + log.log(Level.FINE, "Testing connection to database: {0}", dbName);
87.468 +
87.469 + boolean succesfullyConnected = false;
87.470 + boolean succesfullyConfigured = false;
87.471 + String productName = null;
87.472 + String productVersion = null;
87.473 +
87.474 + try {
87.475 + DatabaseDefinition dd = configurationProvider.getConfiguration().getDatabase(dbName);
87.476 + log.log(Level.FINE, "Database definition was loaded from configuration");
87.477 + succesfullyConfigured = true;
87.478 + try (DatabaseConnection dc = dd.connect(options.getDatabaseProperties())) {
87.479 + succesfullyConnected = dc.test();
87.480 + productName = dc.getProductName();
87.481 + productVersion = dc.getProductVersion();
87.482 + }
87.483 + log.log(Level.FINE, "Database connection test was successful");
87.484 + } catch (ConfigurationException | SQLException | RuntimeException e) {
87.485 + log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
87.486 + }
87.487 +
87.488 + return new Object[]{dbName, succesfullyConfigured, succesfullyConnected, productName, productVersion};
87.489 + }
87.490 +
87.491 + private void printResource(String fileName) {
87.492 + try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream(fileName)))) {
87.493 + while (true) {
87.494 + String line = reader.readLine();
87.495 + if (line == null) {
87.496 + break;
87.497 + } else {
87.498 + println(line);
87.499 + }
87.500 + }
87.501 + } catch (Exception e) {
87.502 + log.log(Level.SEVERE, "Unable to print this info. Please see our website for it: " + Constants.WEBSITE, e);
87.503 + }
87.504 + }
87.505 +
87.506 + private void println(String line) {
87.507 + out.println(line);
87.508 + }
87.509 +
87.510 + private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
87.511 + printTable(formatter, header, sql, parameters, data, null);
87.512 + }
87.513 +
87.514 + private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data, final Integer sortByColumn) throws ConfigurationException, FormatterException {
87.515 + printHeader(formatter, header, sql, parameters);
87.516 +
87.517 + if (sortByColumn != null) {
87.518 + Collections.sort(data, new Comparator<Object[]>() {
87.519 +
87.520 + @Override
87.521 + public int compare(Object[] o1, Object[] o2) {
87.522 + String s1 = String.valueOf(o1[sortByColumn]);
87.523 + String s2 = String.valueOf(o2[sortByColumn]);
87.524 + return s1.compareTo(s2);
87.525 + }
87.526 + });
87.527 + }
87.528 +
87.529 + for (Object[] row : data) {
87.530 + printRow(formatter, row);
87.531 + }
87.532 +
87.533 + printFooter(formatter);
87.534 + }
87.535 +
87.536 + private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
87.537 + formatter.writeStartStatement();
87.538 + if (sql != null) {
87.539 + formatter.writeQuery(sql);
87.540 + if (parameters != null) {
87.541 + formatter.writeParameters(parameters);
87.542 + }
87.543 + }
87.544 + formatter.writeStartResultSet(header);
87.545 + }
87.546 +
87.547 + private void printRow(Formatter formatter, Object[] row) {
87.548 + formatter.writeStartRow();
87.549 + for (Object cell : row) {
87.550 + formatter.writeColumnValue(cell);
87.551 + }
87.552 + formatter.writeEndRow();
87.553 + }
87.554 +
87.555 + private void printFooter(Formatter formatter) {
87.556 + formatter.writeEndResultSet();
87.557 + formatter.writeEndStatement();
87.558 + }
87.559 +
87.560 + private Formatter getFormatter() throws ConfigurationException, FormatterException {
87.561 + String formatterName = options.getFormatterName();
87.562 + formatterName = formatterName == null ? Configuration.DEFAULT_FORMATTER_PREFETCHING : formatterName;
87.563 + FormatterDefinition fd = configurationProvider.getConfiguration().getFormatter(formatterName);
87.564 + FormatterContext context = new FormatterContext(out, options.getFormatterProperties());
87.565 + return fd.getInstance(context);
87.566 + }
87.567 +
87.568 + private ColumnsHeader constructHeader(HeaderField... fields) throws FormatterException {
87.569 + try {
87.570 + RowSetMetaDataImpl metaData = new RowSetMetaDataImpl();
87.571 + metaData.setColumnCount(fields.length);
87.572 +
87.573 + for (int i = 0; i < fields.length; i++) {
87.574 + HeaderField hf = fields[i];
87.575 + int sqlIndex = i + 1;
87.576 + metaData.setColumnName(sqlIndex, hf.name);
87.577 + metaData.setColumnLabel(sqlIndex, hf.name);
87.578 + metaData.setColumnType(sqlIndex, hf.type.getCode());
87.579 + metaData.setColumnTypeName(sqlIndex, hf.type.name());
87.580 + }
87.581 +
87.582 + return new ColumnsHeader(metaData);
87.583 + } catch (SQLException e) {
87.584 + throw new FormatterException("Error while constructing table headers", e);
87.585 + }
87.586 + }
87.587 +
87.588 + private static class HeaderField {
87.589 +
87.590 + String name;
87.591 + SQLType type;
87.592 +
87.593 + public HeaderField(String name, SQLType type) {
87.594 + this.name = name;
87.595 + this.type = type;
87.596 + }
87.597 + }
87.598 +
87.599 + public enum InfoType {
87.600 +
87.601 + HELP {
87.602 + @Override
87.603 + public void showInfo(InfoLister infoLister) {
87.604 + infoLister.printResource(Constants.HELP_FILE);
87.605 + }
87.606 + },
87.607 + VERSION {
87.608 + @Override
87.609 + public void showInfo(InfoLister infoLister) {
87.610 + infoLister.printResource(Constants.VERSION_FILE);
87.611 + }
87.612 + },
87.613 + LICENSE {
87.614 + @Override
87.615 + public void showInfo(InfoLister infoLister) {
87.616 + infoLister.printResource(Constants.LICENSE_FILE);
87.617 + }
87.618 + },
87.619 + JAVA_PROPERTIES {
87.620 + @Override
87.621 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.622 + infoLister.listJavaProperties();
87.623 + }
87.624 + },
87.625 + ENVIRONMENT_VARIABLES {
87.626 + @Override
87.627 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.628 + infoLister.listEnvironmentVariables();
87.629 + }
87.630 + },
87.631 + FORMATTERS {
87.632 + @Override
87.633 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.634 + infoLister.listFormatters();
87.635 + }
87.636 + },
87.637 + FORMATTER_PROPERTIES {
87.638 + @Override
87.639 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.640 + infoLister.listFormatterProperties();
87.641 + }
87.642 + },
87.643 + TYPES {
87.644 + @Override
87.645 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.646 + infoLister.listTypes();
87.647 + }
87.648 + },
87.649 + JDBC_DRIVERS {
87.650 + @Override
87.651 + public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
87.652 + infoLister.listJdbcDrivers();
87.653 + }
87.654 + },
87.655 + JDBC_PROPERTIES {
87.656 + @Override
87.657 + public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
87.658 + infoLister.listJdbcProperties();
87.659 + }
87.660 + },
87.661 + DATABASES {
87.662 + @Override
87.663 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.664 + infoLister.listDatabases();
87.665 + }
87.666 + },
87.667 + CONNECTION {
87.668 + @Override
87.669 + public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
87.670 + infoLister.testConnections();
87.671 + }
87.672 + };
87.673 +
87.674 + public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
87.675 + }
87.676 +}
88.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
88.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/InvalidOptionsException.java Mon Mar 04 20:15:24 2019 +0100
88.3 @@ -0,0 +1,66 @@
88.4 +/**
88.5 + * SQL-DK
88.6 + * Copyright © 2013 František Kučera (frantovo.cz)
88.7 + *
88.8 + * This program is free software: you can redistribute it and/or modify
88.9 + * it under the terms of the GNU General Public License as published by
88.10 + * the Free Software Foundation, either version 3 of the License, or
88.11 + * (at your option) any later version.
88.12 + *
88.13 + * This program is distributed in the hope that it will be useful,
88.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
88.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88.16 + * GNU General Public License for more details.
88.17 + *
88.18 + * You should have received a copy of the GNU General Public License
88.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
88.20 + */
88.21 +package info.globalcode.sql.dk;
88.22 +
88.23 +import java.util.ArrayList;
88.24 +import java.util.Collection;
88.25 +import java.util.Collections;
88.26 +
88.27 +/**
88.28 + *
88.29 + * @author Ing. František Kučera (frantovo.cz)
88.30 + */
88.31 +public class InvalidOptionsException extends Exception {
88.32 +
88.33 + private final Collection<OptionProblem> problems = new ArrayList<>();
88.34 +
88.35 + public Collection<OptionProblem> getProblems() {
88.36 + return Collections.unmodifiableCollection(problems);
88.37 + }
88.38 +
88.39 + public void addProblem(OptionProblem p) {
88.40 + problems.add(p);
88.41 + }
88.42 +
88.43 + public boolean hasProblems() {
88.44 + return !problems.isEmpty();
88.45 + }
88.46 +
88.47 + public static class OptionProblem {
88.48 +
88.49 + private String description;
88.50 + private Throwable exception;
88.51 +
88.52 + public OptionProblem(String description) {
88.53 + this.description = description;
88.54 + }
88.55 +
88.56 + public OptionProblem(String description, Throwable exception) {
88.57 + this.description = description;
88.58 + this.exception = exception;
88.59 + }
88.60 +
88.61 + public String getDescription() {
88.62 + return description;
88.63 + }
88.64 +
88.65 + public Throwable getException() {
88.66 + return exception;
88.67 + }
88.68 + }
88.69 +}
89.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
89.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/NamedParameter.java Mon Mar 04 20:15:24 2019 +0100
89.3 @@ -0,0 +1,48 @@
89.4 +/**
89.5 + * SQL-DK
89.6 + * Copyright © 2013 František Kučera (frantovo.cz)
89.7 + *
89.8 + * This program is free software: you can redistribute it and/or modify
89.9 + * it under the terms of the GNU General Public License as published by
89.10 + * the Free Software Foundation, either version 3 of the License, or
89.11 + * (at your option) any later version.
89.12 + *
89.13 + * This program is distributed in the hope that it will be useful,
89.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
89.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
89.16 + * GNU General Public License for more details.
89.17 + *
89.18 + * You should have received a copy of the GNU General Public License
89.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
89.20 + */
89.21 +package info.globalcode.sql.dk;
89.22 +
89.23 +import info.globalcode.sql.dk.configuration.NameIdentified;
89.24 +
89.25 +/**
89.26 + *
89.27 + * @author Ing. František Kučera (frantovo.cz)
89.28 + */
89.29 +public class NamedParameter extends Parameter implements NameIdentified {
89.30 +
89.31 + private String name;
89.32 +
89.33 + public NamedParameter(String name, Object value, SQLType type) {
89.34 + super(value, type);
89.35 + this.name = name;
89.36 + }
89.37 +
89.38 + @Override
89.39 + public String getName() {
89.40 + return name;
89.41 + }
89.42 +
89.43 + public void setName(String name) {
89.44 + this.name = name;
89.45 + }
89.46 +
89.47 + @Override
89.48 + public String toString() {
89.49 + return "NamedParameter {" + name + " = " + getValue() + "; " + getType() + "}";
89.50 + }
89.51 +}
90.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
90.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/Parameter.java Mon Mar 04 20:15:24 2019 +0100
90.3 @@ -0,0 +1,69 @@
90.4 +/**
90.5 + * SQL-DK
90.6 + * Copyright © 2013 František Kučera (frantovo.cz)
90.7 + *
90.8 + * This program is free software: you can redistribute it and/or modify
90.9 + * it under the terms of the GNU General Public License as published by
90.10 + * the Free Software Foundation, either version 3 of the License, or
90.11 + * (at your option) any later version.
90.12 + *
90.13 + * This program is distributed in the hope that it will be useful,
90.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
90.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90.16 + * GNU General Public License for more details.
90.17 + *
90.18 + * You should have received a copy of the GNU General Public License
90.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
90.20 + */
90.21 +package info.globalcode.sql.dk;
90.22 +
90.23 +import java.sql.Types;
90.24 +
90.25 +/**
90.26 + * Parameter for {@linkplain SQLCommand}
90.27 + *
90.28 + * @author Ing. František Kučera (frantovo.cz)
90.29 + */
90.30 +public class Parameter {
90.31 +
90.32 + /**
90.33 + * @see Types
90.34 + */
90.35 + public static final SQLType DEFAULT_TYPE = SQLType.VARCHAR;
90.36 + private Object value;
90.37 + private SQLType type;
90.38 +
90.39 + public Parameter() {
90.40 + }
90.41 +
90.42 + public Parameter(Object value, SQLType type) {
90.43 + this.value = value;
90.44 + if (type == null) {
90.45 + this.type = DEFAULT_TYPE;
90.46 + } else {
90.47 + this.type = type;
90.48 + }
90.49 + }
90.50 +
90.51 + public Object getValue() {
90.52 + return value;
90.53 + }
90.54 +
90.55 + public void setValue(Object value) {
90.56 + this.value = value;
90.57 + }
90.58 +
90.59 + /**
90.60 + * @see java.sql.Types
90.61 + */
90.62 + public SQLType getType() {
90.63 + return type;
90.64 + }
90.65 +
90.66 + /**
90.67 + * @see java.sql.Types
90.68 + */
90.69 + public void setType(SQLType type) {
90.70 + this.type = type;
90.71 + }
90.72 +}
91.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
91.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/SQLCommand.java Mon Mar 04 20:15:24 2019 +0100
91.3 @@ -0,0 +1,49 @@
91.4 +/**
91.5 + * SQL-DK
91.6 + * Copyright © 2013 František Kučera (frantovo.cz)
91.7 + *
91.8 + * This program is free software: you can redistribute it and/or modify
91.9 + * it under the terms of the GNU General Public License as published by
91.10 + * the Free Software Foundation, either version 3 of the License, or
91.11 + * (at your option) any later version.
91.12 + *
91.13 + * This program is distributed in the hope that it will be useful,
91.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
91.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
91.16 + * GNU General Public License for more details.
91.17 + *
91.18 + * You should have received a copy of the GNU General Public License
91.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
91.20 + */
91.21 +package info.globalcode.sql.dk;
91.22 +
91.23 +import java.sql.Connection;
91.24 +import java.sql.PreparedStatement;
91.25 +import java.sql.SQLException;
91.26 +import java.util.List;
91.27 +
91.28 +/**
91.29 + * Represents SQL string and its parameters (if there are any).
91.30 + *
91.31 + * @author Ing. František Kučera (frantovo.cz)
91.32 + */
91.33 +public abstract class SQLCommand {
91.34 +
91.35 + private String query;
91.36 +
91.37 + public SQLCommand(String query) {
91.38 + this.query = query;
91.39 + }
91.40 +
91.41 + public PreparedStatement prepareStatement(Connection c) throws SQLException {
91.42 + return c.prepareStatement(query);
91.43 + }
91.44 +
91.45 + public abstract void parametrize(PreparedStatement ps) throws SQLException;
91.46 +
91.47 + public abstract List<? extends Parameter> getParameters();
91.48 +
91.49 + public String getQuery() {
91.50 + return query;
91.51 + }
91.52 +}
92.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
92.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/SQLCommandNamed.java Mon Mar 04 20:15:24 2019 +0100
92.3 @@ -0,0 +1,155 @@
92.4 +/**
92.5 + * SQL-DK
92.6 + * Copyright © 2013 František Kučera (frantovo.cz)
92.7 + *
92.8 + * This program is free software: you can redistribute it and/or modify
92.9 + * it under the terms of the GNU General Public License as published by
92.10 + * the Free Software Foundation, either version 3 of the License, or
92.11 + * (at your option) any later version.
92.12 + *
92.13 + * This program is distributed in the hope that it will be useful,
92.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
92.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
92.16 + * GNU General Public License for more details.
92.17 + *
92.18 + * You should have received a copy of the GNU General Public License
92.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
92.20 + */
92.21 +package info.globalcode.sql.dk;
92.22 +
92.23 +import static info.globalcode.sql.dk.Functions.findByName;
92.24 +import java.sql.Connection;
92.25 +import java.sql.PreparedStatement;
92.26 +import java.sql.SQLException;
92.27 +import java.util.ArrayList;
92.28 +import java.util.List;
92.29 +import java.util.logging.Level;
92.30 +import java.util.logging.Logger;
92.31 +import java.util.regex.Matcher;
92.32 +import java.util.regex.Pattern;
92.33 +import java.util.regex.PatternSyntaxException;
92.34 +
92.35 +/**
92.36 + * Has named parameters.
92.37 + *
92.38 + * @author Ing. František Kučera (frantovo.cz)
92.39 + */
92.40 +public class SQLCommandNamed extends SQLCommand {
92.41 +
92.42 + private static final Logger log = Logger.getLogger(SQLCommandNamed.class.getName());
92.43 + private String namePrefix;
92.44 + private String nameSuffix;
92.45 + private List<NamedParameter> parameters;
92.46 + private List<NamedParameter> parametersUsed = new ArrayList<>();
92.47 + private StringBuilder updatedQuery;
92.48 + private Pattern pattern;
92.49 + private SQLCommandNumbered numbered;
92.50 +
92.51 + public SQLCommandNamed(String query, List<NamedParameter> parameters, String namePrefix, String nameSuffix) {
92.52 + super(query);
92.53 + this.updatedQuery = new StringBuilder(query.length());
92.54 + this.parameters = parameters;
92.55 + this.namePrefix = namePrefix;
92.56 + this.nameSuffix = nameSuffix;
92.57 + }
92.58 +
92.59 + @Override
92.60 + public PreparedStatement prepareStatement(Connection c) throws SQLException {
92.61 + return getSQLCommandNumbered().prepareStatement(c);
92.62 + }
92.63 +
92.64 + @Override
92.65 + public void parametrize(PreparedStatement ps) throws SQLException {
92.66 + getSQLCommandNumbered().parametrize(ps);
92.67 + }
92.68 +
92.69 + private void prepare() throws SQLException {
92.70 + try {
92.71 + buildPattern();
92.72 + placeParametersAndUpdateQuery();
92.73 + logPossiblyMissingParameters();
92.74 + } catch (PatternSyntaxException e) {
92.75 + throw new SQLException("Name prefix „" + namePrefix + "“ or suffix „" + nameSuffix + "“ contain a wrong regular expression. " + e.getLocalizedMessage(), e);
92.76 + }
92.77 + }
92.78 +
92.79 + /**
92.80 + * @return SQL command with named parameters converted to SQL command with numbered parameters
92.81 + */
92.82 + public SQLCommandNumbered getSQLCommandNumbered() throws SQLException {
92.83 + if (numbered == null) {
92.84 + prepare();
92.85 + numbered = new SQLCommandNumbered(updatedQuery.toString(), parametersUsed);
92.86 + }
92.87 +
92.88 + return numbered;
92.89 + }
92.90 +
92.91 + /**
92.92 + * Builds a regexp pattern that matches all parameter names (with prefix/suffix) and which has
92.93 + * one group: parameter name (without prefix/suffix)
92.94 + */
92.95 + private void buildPattern() throws PatternSyntaxException {
92.96 + StringBuilder patternString = new StringBuilder();
92.97 +
92.98 + patternString.append(namePrefix);
92.99 + patternString.append("(?<paramName>");
92.100 + for (int i = 0; i < parameters.size(); i++) {
92.101 + patternString.append(Pattern.quote(parameters.get(i).getName()));
92.102 + if (i < parameters.size() - 1) {
92.103 + patternString.append("|");
92.104 + }
92.105 + }
92.106 + patternString.append(")");
92.107 + patternString.append(nameSuffix);
92.108 +
92.109 + pattern = Pattern.compile(patternString.toString());
92.110 + }
92.111 +
92.112 + private void placeParametersAndUpdateQuery() {
92.113 + final String originalQuery = getQuery();
92.114 + Matcher m = pattern.matcher(originalQuery);
92.115 +
92.116 + int lastPosition = 0;
92.117 + while (m.find(lastPosition)) {
92.118 + String name = m.group("paramName");
92.119 +
92.120 + updatedQuery.append(originalQuery.substring(lastPosition, m.start()));
92.121 + updatedQuery.append("?");
92.122 +
92.123 + parametersUsed.add(findByName(parameters, name));
92.124 +
92.125 + lastPosition = m.end();
92.126 + }
92.127 + updatedQuery.append(originalQuery.substring(lastPosition, originalQuery.length()));
92.128 +
92.129 + for (NamedParameter definedParameter : parameters) {
92.130 + if (findByName(parametersUsed, definedParameter.getName()) == null) {
92.131 + /**
92.132 + * User can have predefined set of parameters and use them with different SQL
92.133 + * queries that use only subset of these parameters → just warning, not exception.
92.134 + */
92.135 + log.log(Level.WARNING, "Parameter „{0}“ is defined but not used in the query: „{1}“", new Object[]{definedParameter.getName(), originalQuery});
92.136 + }
92.137 + }
92.138 + }
92.139 +
92.140 + private void logPossiblyMissingParameters() {
92.141 + Pattern p = Pattern.compile(namePrefix + "(?<paramName>.+?)" + nameSuffix);
92.142 + Matcher m = p.matcher(updatedQuery);
92.143 + int lastPosition = 0;
92.144 + while (m.find(lastPosition)) {
92.145 + /**
92.146 + * We have not parsed and understood the SQL query; the parameter-like looking string
92.147 + * could be inside a literal part of the query → just warning, not exception.
92.148 + */
92.149 + log.log(Level.WARNING, "Possibly missing parameter „{0}“ in the query: „{1}“", new Object[]{m.group("paramName"), getQuery()});
92.150 + lastPosition = m.end();
92.151 + }
92.152 + }
92.153 +
92.154 + @Override
92.155 + public List<NamedParameter> getParameters() {
92.156 + return parameters;
92.157 + }
92.158 +}
93.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
93.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/SQLCommandNumbered.java Mon Mar 04 20:15:24 2019 +0100
93.3 @@ -0,0 +1,51 @@
93.4 +/**
93.5 + * SQL-DK
93.6 + * Copyright © 2013 František Kučera (frantovo.cz)
93.7 + *
93.8 + * This program is free software: you can redistribute it and/or modify
93.9 + * it under the terms of the GNU General Public License as published by
93.10 + * the Free Software Foundation, either version 3 of the License, or
93.11 + * (at your option) any later version.
93.12 + *
93.13 + * This program is distributed in the hope that it will be useful,
93.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
93.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93.16 + * GNU General Public License for more details.
93.17 + *
93.18 + * You should have received a copy of the GNU General Public License
93.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
93.20 + */
93.21 +package info.globalcode.sql.dk;
93.22 +
93.23 +import static info.globalcode.sql.dk.Functions.notNull;
93.24 +import java.sql.PreparedStatement;
93.25 +import java.sql.SQLException;
93.26 +import java.util.List;
93.27 +
93.28 +/**
93.29 + * Has ordinal/numbered parameters.
93.30 + *
93.31 + * @author Ing. František Kučera (frantovo.cz)
93.32 + */
93.33 +public class SQLCommandNumbered extends SQLCommand {
93.34 +
93.35 + private List<? extends Parameter> parameters;
93.36 +
93.37 + public SQLCommandNumbered(String query, List<? extends Parameter> parameters) {
93.38 + super(query);
93.39 + this.parameters = parameters;
93.40 + }
93.41 +
93.42 + @Override
93.43 + public void parametrize(PreparedStatement ps) throws SQLException {
93.44 + int i = 1;
93.45 + for (Parameter p : notNull(parameters)) {
93.46 + ps.setObject(i++, p.getValue(), p.getType().getCode());
93.47 + }
93.48 + }
93.49 +
93.50 + @Override
93.51 + public List<? extends Parameter> getParameters() {
93.52 + return parameters;
93.53 + }
93.54 +}
94.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/SQLType.java Mon Mar 04 20:15:24 2019 +0100
94.3 @@ -0,0 +1,95 @@
94.4 +/**
94.5 + * SQL-DK
94.6 + * Copyright © 2013 František Kučera (frantovo.cz)
94.7 + *
94.8 + * This program is free software: you can redistribute it and/or modify
94.9 + * it under the terms of the GNU General Public License as published by
94.10 + * the Free Software Foundation, either version 3 of the License, or
94.11 + * (at your option) any later version.
94.12 + *
94.13 + * This program is distributed in the hope that it will be useful,
94.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
94.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94.16 + * GNU General Public License for more details.
94.17 + *
94.18 + * You should have received a copy of the GNU General Public License
94.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
94.20 + */
94.21 +package info.globalcode.sql.dk;
94.22 +
94.23 +import java.sql.Types;
94.24 +
94.25 +/**
94.26 + * Data types of SQL parameters.
94.27 + *
94.28 + * @author Ing. František Kučera (frantovo.cz)
94.29 + */
94.30 +public enum SQLType {
94.31 +
94.32 + /**
94.33 + * Names must be upper case – user input is also converted to upper case → case insensitive
94.34 + */
94.35 + BIT(Types.BIT),
94.36 + TINYINT(Types.TINYINT),
94.37 + SMALLINT(Types.SMALLINT),
94.38 + INTEGER(Types.INTEGER),
94.39 + BIGINT(Types.BIGINT),
94.40 + FLOAT(Types.FLOAT),
94.41 + REAL(Types.REAL),
94.42 + DOUBLE(Types.DOUBLE),
94.43 + NUMERIC(Types.NUMERIC),
94.44 + DECIMAL(Types.DECIMAL),
94.45 + CHAR(Types.CHAR),
94.46 + VARCHAR(Types.VARCHAR),
94.47 + LONGVARCHAR(Types.LONGVARCHAR),
94.48 + DATE(Types.DATE),
94.49 + TIME(Types.TIME),
94.50 + TIMESTAMP(Types.TIMESTAMP),
94.51 + BINARY(Types.BINARY),
94.52 + VARBINARY(Types.VARBINARY),
94.53 + LONGVARBINARY(Types.LONGVARBINARY),
94.54 + NULL(Types.NULL),
94.55 + OTHER(Types.OTHER),
94.56 + JAVA_OBJECT(Types.JAVA_OBJECT),
94.57 + DISTINCT(Types.DISTINCT),
94.58 + STRUCT(Types.STRUCT),
94.59 + ARRAY(Types.ARRAY),
94.60 + BLOB(Types.BLOB),
94.61 + CLOB(Types.CLOB),
94.62 + REF(Types.REF),
94.63 + DATALINK(Types.DATALINK),
94.64 + BOOLEAN(Types.BOOLEAN),
94.65 + ROWID(Types.ROWID),
94.66 + NCHAR(Types.NCHAR),
94.67 + NVARCHAR(Types.NVARCHAR),
94.68 + LONGNVARCHAR(Types.LONGNVARCHAR),
94.69 + NCLOB(Types.NCLOB),
94.70 + SQLXML(Types.SQLXML);
94.71 + /** value from java.sql.Types */
94.72 + private int code;
94.73 +
94.74 + private SQLType(int code) {
94.75 + this.code = code;
94.76 + }
94.77 +
94.78 + /**
94.79 + * @see java.sql.Types.Types
94.80 + */
94.81 + public int getCode() {
94.82 + return code;
94.83 + }
94.84 +
94.85 + /**
94.86 + * @param code see {@linkplain java.sql.Types.Types}
94.87 + * @return found SQLType
94.88 + * @throws IllegalArgumentException if no data type has given code
94.89 + */
94.90 + public static SQLType valueOf(int code) {
94.91 + for (SQLType t : values()) {
94.92 + if (t.code == code) {
94.93 + return t;
94.94 + }
94.95 + }
94.96 + throw new IllegalArgumentException("No data type has code: " + code);
94.97 + }
94.98 +}
95.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/Xmlns.java Mon Mar 04 20:15:24 2019 +0100
95.3 @@ -0,0 +1,33 @@
95.4 +/**
95.5 + * SQL-DK
95.6 + * Copyright © 2013 František Kučera (frantovo.cz)
95.7 + *
95.8 + * This program is free software: you can redistribute it and/or modify
95.9 + * it under the terms of the GNU General Public License as published by
95.10 + * the Free Software Foundation, either version 3 of the License, or
95.11 + * (at your option) any later version.
95.12 + *
95.13 + * This program is distributed in the hope that it will be useful,
95.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
95.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95.16 + * GNU General Public License for more details.
95.17 + *
95.18 + * You should have received a copy of the GNU General Public License
95.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
95.20 + */
95.21 +package info.globalcode.sql.dk;
95.22 +
95.23 +/**
95.24 + * XML namespaces
95.25 + *
95.26 + * @author Ing. František Kučera (frantovo.cz)
95.27 + */
95.28 +public class Xmlns {
95.29 +
95.30 + public static final String CONFIGURATION = "https://sql-dk.globalcode.info/xmlns/configuration";
95.31 + public static final String BATCH_RESULT = "https://sql-dk.globalcode.info/xmlns/batchResult";
95.32 + public static final String XHTML = "http://www.w3.org/1999/xhtml";
95.33 +
95.34 + private Xmlns() {
95.35 + }
95.36 +}
96.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
96.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/batch/Batch.java Mon Mar 04 20:15:24 2019 +0100
96.3 @@ -0,0 +1,32 @@
96.4 +/**
96.5 + * SQL-DK
96.6 + * Copyright © 2013 František Kučera (frantovo.cz)
96.7 + *
96.8 + * This program is free software: you can redistribute it and/or modify
96.9 + * it under the terms of the GNU General Public License as published by
96.10 + * the Free Software Foundation, either version 3 of the License, or
96.11 + * (at your option) any later version.
96.12 + *
96.13 + * This program is distributed in the hope that it will be useful,
96.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
96.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96.16 + * GNU General Public License for more details.
96.17 + *
96.18 + * You should have received a copy of the GNU General Public License
96.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
96.20 + */
96.21 +package info.globalcode.sql.dk.batch;
96.22 +
96.23 +import info.globalcode.sql.dk.SQLCommand;
96.24 +
96.25 +/**
96.26 + * Iterator which reads SQL commands from encoded (serialized) batch.
96.27 + *
96.28 + * @author Ing. František Kučera (frantovo.cz)
96.29 + */
96.30 +public interface Batch {
96.31 +
96.32 + public boolean hasNext() throws BatchException;
96.33 +
96.34 + public SQLCommand next() throws BatchException;
96.35 +}
97.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
97.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/batch/BatchConstants.java Mon Mar 04 20:15:24 2019 +0100
97.3 @@ -0,0 +1,35 @@
97.4 +/**
97.5 + * SQL-DK
97.6 + * Copyright © 2014 František Kučera (frantovo.cz)
97.7 + *
97.8 + * This program is free software: you can redistribute it and/or modify
97.9 + * it under the terms of the GNU General Public License as published by
97.10 + * the Free Software Foundation, either version 3 of the License, or
97.11 + * (at your option) any later version.
97.12 + *
97.13 + * This program is distributed in the hope that it will be useful,
97.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
97.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
97.16 + * GNU General Public License for more details.
97.17 + *
97.18 + * You should have received a copy of the GNU General Public License
97.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
97.20 + */
97.21 +package info.globalcode.sql.dk.batch;
97.22 +
97.23 +import java.nio.charset.Charset;
97.24 +import java.nio.charset.StandardCharsets;
97.25 +
97.26 +/**
97.27 + *
97.28 + * @author Ing. František Kučera (frantovo.cz)
97.29 + */
97.30 +public class BatchConstants {
97.31 +
97.32 + public static final Charset CHARSET = StandardCharsets.UTF_8;
97.33 + public static final byte VERSION = 0x01;
97.34 + public static final byte[] BATCH_HEADER = {0x00, 0x53, 0x51, 0x4C, VERSION};
97.35 +
97.36 + private BatchConstants() {
97.37 + }
97.38 +}
98.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
98.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/batch/BatchDecoder.java Mon Mar 04 20:15:24 2019 +0100
98.3 @@ -0,0 +1,108 @@
98.4 +/**
98.5 + * SQL-DK
98.6 + * Copyright © 2014 František Kučera (frantovo.cz)
98.7 + *
98.8 + * This program is free software: you can redistribute it and/or modify
98.9 + * it under the terms of the GNU General Public License as published by
98.10 + * the Free Software Foundation, either version 3 of the License, or
98.11 + * (at your option) any later version.
98.12 + *
98.13 + * This program is distributed in the hope that it will be useful,
98.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
98.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98.16 + * GNU General Public License for more details.
98.17 + *
98.18 + * You should have received a copy of the GNU General Public License
98.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
98.20 + */
98.21 +package info.globalcode.sql.dk.batch;
98.22 +
98.23 +import info.globalcode.sql.dk.Parameter;
98.24 +import info.globalcode.sql.dk.SQLCommand;
98.25 +import info.globalcode.sql.dk.SQLCommandNumbered;
98.26 +import java.io.DataInputStream;
98.27 +import java.io.InputStream;
98.28 +import static info.globalcode.sql.dk.batch.BatchConstants.*;
98.29 +import static info.globalcode.sql.dk.Functions.toHex;
98.30 +import info.globalcode.sql.dk.SQLType;
98.31 +import java.io.IOException;
98.32 +import java.util.ArrayList;
98.33 +import java.util.Arrays;
98.34 +import java.util.List;
98.35 +
98.36 +/**
98.37 + *
98.38 + * @author Ing. František Kučera (frantovo.cz)
98.39 + */
98.40 +public class BatchDecoder {
98.41 +
98.42 + public Batch decode(InputStream in) throws BatchException {
98.43 + return new BatchFromStream(new DataInputStream(in));
98.44 + }
98.45 +
98.46 + private class BatchFromStream implements Batch {
98.47 +
98.48 + private DataInputStream in;
98.49 + private boolean hasNext;
98.50 +
98.51 + public BatchFromStream(DataInputStream in) throws BatchException {
98.52 + this.in = in;
98.53 + hasNext = verifyHeader();
98.54 + }
98.55 +
98.56 + @Override
98.57 + public boolean hasNext() throws BatchException {
98.58 + return hasNext;
98.59 + }
98.60 +
98.61 + @Override
98.62 + public SQLCommand next() throws BatchException {
98.63 + try {
98.64 + String sql = readNextString();
98.65 +
98.66 + int paramCount = in.readInt();
98.67 + List<Parameter> parameters = new ArrayList<>(paramCount);
98.68 +
98.69 + for (int i = 0; i < paramCount; i++) {
98.70 + SQLType type = SQLType.valueOf(in.readInt());
98.71 + String value = readNextString();
98.72 + parameters.add(new Parameter(value, type));
98.73 + }
98.74 +
98.75 + hasNext = verifyHeader();
98.76 +
98.77 + SQLCommand sqlCommand = new SQLCommandNumbered(sql, parameters);
98.78 + return sqlCommand;
98.79 + } catch (IOException e) {
98.80 + throw new BatchException("Unable to read batch", e);
98.81 + }
98.82 + }
98.83 +
98.84 + private String readNextString() throws IOException {
98.85 + byte[] buffer = new byte[in.readInt()];
98.86 + in.read(buffer);
98.87 + return new String(buffer, CHARSET);
98.88 + }
98.89 +
98.90 + /**
98.91 + * @return true if correct batch header was found | false if EOF was found
98.92 + * @throws BatchException if unexpected data was found (not batch header nor EOF)
98.93 + */
98.94 + private boolean verifyHeader() throws BatchException {
98.95 + try {
98.96 + byte[] buffer = new byte[BATCH_HEADER.length];
98.97 + int bytesRead = in.read(buffer);
98.98 +
98.99 + if (bytesRead == BATCH_HEADER.length && Arrays.equals(buffer, BATCH_HEADER)) {
98.100 + return true;
98.101 + } else if (bytesRead == -1) {
98.102 + return false;
98.103 + } else {
98.104 + throw new BatchException("This is not SQL-DK batch: " + toHex(buffer));
98.105 + }
98.106 + } catch (IOException e) {
98.107 + throw new BatchException("Unable to read batch header", e);
98.108 + }
98.109 + }
98.110 + }
98.111 +}
99.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
99.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/batch/BatchEncoder.java Mon Mar 04 20:15:24 2019 +0100
99.3 @@ -0,0 +1,83 @@
99.4 +/**
99.5 + * SQL-DK
99.6 + * Copyright © 2014 František Kučera (frantovo.cz)
99.7 + *
99.8 + * This program is free software: you can redistribute it and/or modify
99.9 + * it under the terms of the GNU General Public License as published by
99.10 + * the Free Software Foundation, either version 3 of the License, or
99.11 + * (at your option) any later version.
99.12 + *
99.13 + * This program is distributed in the hope that it will be useful,
99.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
99.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
99.16 + * GNU General Public License for more details.
99.17 + *
99.18 + * You should have received a copy of the GNU General Public License
99.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
99.20 + */
99.21 +package info.globalcode.sql.dk.batch;
99.22 +
99.23 +import info.globalcode.sql.dk.Parameter;
99.24 +import info.globalcode.sql.dk.SQLCommand;
99.25 +import info.globalcode.sql.dk.SQLCommandNamed;
99.26 +import java.io.DataOutputStream;
99.27 +import java.io.IOException;
99.28 +import java.io.OutputStream;
99.29 +import static info.globalcode.sql.dk.batch.BatchConstants.*;
99.30 +import java.io.ByteArrayOutputStream;
99.31 +import java.sql.SQLException;
99.32 +import java.util.List;
99.33 +
99.34 +/**
99.35 + *
99.36 + * @author Ing. František Kučera (frantovo.cz)
99.37 + */
99.38 +public class BatchEncoder {
99.39 +
99.40 + public int encode(SQLCommand sqlCommand, OutputStream out) throws BatchException {
99.41 + try {
99.42 + ByteArrayOutputStream bufferAOS = new ByteArrayOutputStream();
99.43 + DataOutputStream buffer = new DataOutputStream(bufferAOS);
99.44 +
99.45 + buffer.write(BATCH_HEADER);
99.46 +
99.47 + if (sqlCommand instanceof SQLCommandNamed) {
99.48 + sqlCommand = ((SQLCommandNamed) sqlCommand).getSQLCommandNumbered();
99.49 + }
99.50 +
99.51 + writeNextString(sqlCommand.getQuery(), buffer);
99.52 +
99.53 + List<? extends Parameter> parameters = sqlCommand.getParameters();
99.54 +
99.55 + buffer.writeInt(parameters.size());
99.56 +
99.57 + for (Parameter p : parameters) {
99.58 + buffer.writeInt(p.getType().getCode());
99.59 + writeNextString((String) p.getValue(), buffer); // parameters are encoded before any preprocessing
99.60 + }
99.61 +
99.62 + buffer.flush();
99.63 + bufferAOS.writeTo(out);
99.64 + out.flush();
99.65 + return bufferAOS.size();
99.66 + } catch (IOException e) {
99.67 + throw new BatchException("Unable to write SQL command: " + sqlCommand, e);
99.68 + } catch (SQLException e) {
99.69 + throw new BatchException("Unable to converd named SQL command to numbered: " + sqlCommand, e);
99.70 + }
99.71 + }
99.72 +
99.73 + private void writeNextString(String s, DataOutputStream out) throws IOException {
99.74 + byte[] bytes = toBytes(s);
99.75 + out.writeInt(bytes.length);
99.76 + out.write(bytes);
99.77 + }
99.78 +
99.79 + private static byte[] toBytes(String s) {
99.80 + if (s == null) {
99.81 + return new byte[]{};
99.82 + } else {
99.83 + return s.getBytes(CHARSET);
99.84 + }
99.85 + }
99.86 +}
100.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
100.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/batch/BatchException.java Mon Mar 04 20:15:24 2019 +0100
100.3 @@ -0,0 +1,42 @@
100.4 +/**
100.5 + * SQL-DK
100.6 + * Copyright © 2014 František Kučera (frantovo.cz)
100.7 + *
100.8 + * This program is free software: you can redistribute it and/or modify
100.9 + * it under the terms of the GNU General Public License as published by
100.10 + * the Free Software Foundation, either version 3 of the License, or
100.11 + * (at your option) any later version.
100.12 + *
100.13 + * This program is distributed in the hope that it will be useful,
100.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
100.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100.16 + * GNU General Public License for more details.
100.17 + *
100.18 + * You should have received a copy of the GNU General Public License
100.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
100.20 + */
100.21 +package info.globalcode.sql.dk.batch;
100.22 +
100.23 +import info.globalcode.sql.dk.DKException;
100.24 +
100.25 +/**
100.26 + *
100.27 + * @author Ing. František Kučera (frantovo.cz)
100.28 + */
100.29 +public class BatchException extends DKException {
100.30 +
100.31 + public BatchException() {
100.32 + }
100.33 +
100.34 + public BatchException(String message) {
100.35 + super(message);
100.36 + }
100.37 +
100.38 + public BatchException(Throwable cause) {
100.39 + super(cause);
100.40 + }
100.41 +
100.42 + public BatchException(String message, Throwable cause) {
100.43 + super(message, cause);
100.44 + }
100.45 +}
101.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/CommandArgument.java Mon Mar 04 20:15:24 2019 +0100
101.3 @@ -0,0 +1,82 @@
101.4 +/**
101.5 + * SQL-DK
101.6 + * Copyright © 2015 František Kučera (frantovo.cz)
101.7 + *
101.8 + * This program is free software: you can redistribute it and/or modify
101.9 + * it under the terms of the GNU General Public License as published by
101.10 + * the Free Software Foundation, either version 3 of the License, or
101.11 + * (at your option) any later version.
101.12 + *
101.13 + * This program is distributed in the hope that it will be useful,
101.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
101.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
101.16 + * GNU General Public License for more details.
101.17 + *
101.18 + * You should have received a copy of the GNU General Public License
101.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
101.20 + */
101.21 +package info.globalcode.sql.dk.configuration;
101.22 +
101.23 +import javax.xml.bind.annotation.XmlAttribute;
101.24 +import javax.xml.bind.annotation.XmlEnum;
101.25 +import javax.xml.bind.annotation.XmlEnumValue;
101.26 +import javax.xml.bind.annotation.XmlValue;
101.27 +
101.28 +/**
101.29 + *
101.30 + * @author Ing. František Kučera (frantovo.cz)
101.31 + */
101.32 +public class CommandArgument {
101.33 +
101.34 + private String value;
101.35 + private TYPE type;
101.36 +
101.37 + @XmlEnum
101.38 + public static enum TYPE {
101.39 +
101.40 + /**
101.41 + * value = literal (text) argument
101.42 + */
101.43 + @XmlEnumValue("literal")
101.44 + LITERAL,
101.45 + /**
101.46 + * value will be substituted by hostname or IP address of the DB server
101.47 + */
101.48 + @XmlEnumValue("host")
101.49 + HOST,
101.50 + /**
101.51 + * value will be substituted by the port of the DB server
101.52 + */
101.53 + @XmlEnumValue("port")
101.54 + PORT,
101.55 + /**
101.56 + * value will be substituted by environmental variable of given name
101.57 + */
101.58 + @XmlEnumValue("env")
101.59 + ENVIRONMENT_VARIABLE,
101.60 + /**
101.61 + * value will be substituted by database property of given name
101.62 + */
101.63 + @XmlEnumValue("dbProperty")
101.64 + DB_PROPERTY;
101.65 + }
101.66 +
101.67 + @XmlValue
101.68 + public String getValue() {
101.69 + return value;
101.70 + }
101.71 +
101.72 + public void setValue(String value) {
101.73 + this.value = value;
101.74 + }
101.75 +
101.76 + @XmlAttribute(name = "type")
101.77 + public TYPE getType() {
101.78 + return type;
101.79 + }
101.80 +
101.81 + public void setType(TYPE type) {
101.82 + this.type = type;
101.83 + }
101.84 +
101.85 +}
102.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/Configuration.java Mon Mar 04 20:15:24 2019 +0100
102.3 @@ -0,0 +1,173 @@
102.4 +/**
102.5 + * SQL-DK
102.6 + * Copyright © 2013 František Kučera (frantovo.cz)
102.7 + *
102.8 + * This program is free software: you can redistribute it and/or modify
102.9 + * it under the terms of the GNU General Public License as published by
102.10 + * the Free Software Foundation, either version 3 of the License, or
102.11 + * (at your option) any later version.
102.12 + *
102.13 + * This program is distributed in the hope that it will be useful,
102.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
102.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102.16 + * GNU General Public License for more details.
102.17 + *
102.18 + * You should have received a copy of the GNU General Public License
102.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
102.20 + */
102.21 +package info.globalcode.sql.dk.configuration;
102.22 +
102.23 +import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
102.24 +import static info.globalcode.sql.dk.Functions.findByName;
102.25 +import info.globalcode.sql.dk.formatting.BarChartFormatter;
102.26 +import info.globalcode.sql.dk.formatting.SilentFormatter;
102.27 +import info.globalcode.sql.dk.formatting.SingleRecordFormatter;
102.28 +import info.globalcode.sql.dk.formatting.SingleValueFormatter;
102.29 +import info.globalcode.sql.dk.formatting.TabularFormatter;
102.30 +import info.globalcode.sql.dk.formatting.TabularPrefetchingFormatter;
102.31 +import info.globalcode.sql.dk.formatting.TabularWrappingFormatter;
102.32 +import info.globalcode.sql.dk.formatting.TeXFormatter;
102.33 +import info.globalcode.sql.dk.formatting.XhtmlFormatter;
102.34 +import info.globalcode.sql.dk.formatting.XmlFormatter;
102.35 +import java.util.ArrayList;
102.36 +import java.util.Collection;
102.37 +import java.util.Collections;
102.38 +import java.util.List;
102.39 +import javax.xml.bind.annotation.XmlElement;
102.40 +import javax.xml.bind.annotation.XmlRootElement;
102.41 +import javax.xml.bind.annotation.XmlTransient;
102.42 +
102.43 +/**
102.44 + * Object representation of user configuration loaded from XML.
102.45 + *
102.46 + * @author Ing. František Kučera (frantovo.cz)
102.47 + */
102.48 +@XmlRootElement(name = "configuration", namespace = CONFIGURATION)
102.49 +public class Configuration {
102.50 +
102.51 + private List<DatabaseDefinition> databases = new ArrayList<>();
102.52 + private List<FormatterDefinition> formatters = new ArrayList<>();
102.53 + /**
102.54 + * is used if no formatter is specified on CLI nor in user configuration
102.55 + */
102.56 + public static final String DEFAULT_FORMATTER = TabularFormatter.NAME;
102.57 + /**
102.58 + * Can be used as default if prefetching is ok – for configuration listings (config is alread in
102.59 + * memory, so this does not matter)
102.60 + */
102.61 + public static final String DEFAULT_FORMATTER_PREFETCHING = TabularPrefetchingFormatter.NAME;
102.62 + private String defaultFormatter;
102.63 + /**
102.64 + * Default list of formatters. Is used if particular name is not found in user configuration.
102.65 + */
102.66 + private static final Collection<FormatterDefinition> buildInFormatters;
102.67 +
102.68 + static {
102.69 + Collection<FormatterDefinition> l = new ArrayList<>();
102.70 + l.add(new FormatterDefinition(SilentFormatter.NAME, SilentFormatter.class.getName()));
102.71 + l.add(new FormatterDefinition(SingleValueFormatter.NAME, SingleValueFormatter.class.getName()));
102.72 + l.add(new FormatterDefinition(SingleRecordFormatter.NAME, SingleRecordFormatter.class.getName()));
102.73 + l.add(new FormatterDefinition(XmlFormatter.NAME, XmlFormatter.class.getName()));
102.74 + l.add(new FormatterDefinition(XhtmlFormatter.NAME, XhtmlFormatter.class.getName()));
102.75 + l.add(new FormatterDefinition(TabularFormatter.NAME, TabularFormatter.class.getName()));
102.76 + l.add(new FormatterDefinition(TabularPrefetchingFormatter.NAME, TabularPrefetchingFormatter.class.getName()));
102.77 + l.add(new FormatterDefinition(TabularWrappingFormatter.NAME, TabularWrappingFormatter.class.getName()));
102.78 + l.add(new FormatterDefinition(TeXFormatter.NAME, TeXFormatter.class.getName()));
102.79 + //l.add(new FormatterDefinition(DsvFormatter.NAME, DsvFormatter.class.getName()));
102.80 + //l.add(new FormatterDefinition(SystemCommandExecutor.NAME, SystemCommandExecutor.class.getName()));
102.81 + l.add(new FormatterDefinition(BarChartFormatter.NAME, BarChartFormatter.class.getName()));
102.82 + buildInFormatters = Collections.unmodifiableCollection(l);
102.83 + }
102.84 +
102.85 + @XmlElement(name = "database", namespace = CONFIGURATION)
102.86 + public List<DatabaseDefinition> getDatabases() {
102.87 + return databases;
102.88 + }
102.89 +
102.90 + public void setDatabases(List<DatabaseDefinition> databases) {
102.91 + this.databases = databases;
102.92 + }
102.93 +
102.94 + /**
102.95 + * @param name
102.96 + * @return
102.97 + * @throws ConfigurationException if no database with this name is configured
102.98 + */
102.99 + public DatabaseDefinition getDatabase(String name) throws ConfigurationException {
102.100 + DatabaseDefinition dd = findByName(databases, name);
102.101 + if (dd == null) {
102.102 + throw new ConfigurationException("Database is not configured: " + name);
102.103 + } else {
102.104 + return dd;
102.105 + }
102.106 + }
102.107 +
102.108 + /**
102.109 + * @return only configured formatters
102.110 + * @see #getBuildInFormatters()
102.111 + * @see #getAllFormatters()
102.112 + */
102.113 + @XmlElement(name = "formatter", namespace = CONFIGURATION)
102.114 + public List<FormatterDefinition> getFormatters() {
102.115 + return formatters;
102.116 + }
102.117 +
102.118 + public void setFormatters(List<FormatterDefinition> formatters) {
102.119 + this.formatters = formatters;
102.120 + }
102.121 +
102.122 + /**
102.123 + * @param name name of desired formatter. Looking for this name in user configuration, then in
102.124 + * buil-in formatters. If null, default from configuration or (if not configured) built-in
102.125 + * default is used.
102.126 + * @return formatter definition
102.127 + * @throws ConfigurationException if no formatter with this name was found
102.128 + */
102.129 + public FormatterDefinition getFormatter(String name) throws ConfigurationException {
102.130 + if (name == null) {
102.131 + return defaultFormatter == null ? getFormatter(DEFAULT_FORMATTER) : getFormatter(defaultFormatter);
102.132 + } else {
102.133 + FormatterDefinition fd = findByName(formatters, name);
102.134 + fd = fd == null ? findByName(buildInFormatters, name) : fd;
102.135 + if (fd == null) {
102.136 + throw new ConfigurationException("Formatter is not configured: " + name);
102.137 + } else {
102.138 + return fd;
102.139 + }
102.140 + }
102.141 + }
102.142 +
102.143 + /**
102.144 + * @return only built-in formatters
102.145 + * @see #getAllFormatters()
102.146 + * @see #getFormatters()
102.147 + */
102.148 + @XmlTransient
102.149 + public Collection<FormatterDefinition> getBuildInFormatters() {
102.150 + return buildInFormatters;
102.151 + }
102.152 +
102.153 + /**
102.154 + * @return built-in + configured formatters
102.155 + * @see #getFormatters()
102.156 + */
102.157 + @XmlTransient
102.158 + public Collection<FormatterDefinition> getAllFormatters() {
102.159 + Collection<FormatterDefinition> allFormatters = new ArrayList<>();
102.160 + allFormatters.addAll(buildInFormatters);
102.161 + allFormatters.addAll(formatters);
102.162 + return allFormatters;
102.163 + }
102.164 +
102.165 + /**
102.166 + * @return name of default formatter, is used if name is not specified on CLI
102.167 + */
102.168 + @XmlElement(name = "defaultFormatter", namespace = CONFIGURATION)
102.169 + public String getDefaultFormatter() {
102.170 + return defaultFormatter;
102.171 + }
102.172 +
102.173 + public void setDefaultFormatter(String defaultFormatter) {
102.174 + this.defaultFormatter = defaultFormatter;
102.175 + }
102.176 +}
103.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/ConfigurationException.java Mon Mar 04 20:15:24 2019 +0100
103.3 @@ -0,0 +1,42 @@
103.4 +/**
103.5 + * SQL-DK
103.6 + * Copyright © 2013 František Kučera (frantovo.cz)
103.7 + *
103.8 + * This program is free software: you can redistribute it and/or modify
103.9 + * it under the terms of the GNU General Public License as published by
103.10 + * the Free Software Foundation, either version 3 of the License, or
103.11 + * (at your option) any later version.
103.12 + *
103.13 + * This program is distributed in the hope that it will be useful,
103.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
103.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
103.16 + * GNU General Public License for more details.
103.17 + *
103.18 + * You should have received a copy of the GNU General Public License
103.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
103.20 + */
103.21 +package info.globalcode.sql.dk.configuration;
103.22 +
103.23 +import info.globalcode.sql.dk.DKException;
103.24 +
103.25 +/**
103.26 + *
103.27 + * @author Ing. František Kučera (frantovo.cz)
103.28 + */
103.29 +public class ConfigurationException extends DKException {
103.30 +
103.31 + public ConfigurationException() {
103.32 + }
103.33 +
103.34 + public ConfigurationException(String message) {
103.35 + super(message);
103.36 + }
103.37 +
103.38 + public ConfigurationException(Throwable cause) {
103.39 + super(cause);
103.40 + }
103.41 +
103.42 + public ConfigurationException(String message, Throwable cause) {
103.43 + super(message, cause);
103.44 + }
103.45 +}
104.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
104.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/ConfigurationProvider.java Mon Mar 04 20:15:24 2019 +0100
104.3 @@ -0,0 +1,28 @@
104.4 +/**
104.5 + * SQL-DK
104.6 + * Copyright © 2013 František Kučera (frantovo.cz)
104.7 + *
104.8 + * This program is free software: you can redistribute it and/or modify
104.9 + * it under the terms of the GNU General Public License as published by
104.10 + * the Free Software Foundation, either version 3 of the License, or
104.11 + * (at your option) any later version.
104.12 + *
104.13 + * This program is distributed in the hope that it will be useful,
104.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
104.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
104.16 + * GNU General Public License for more details.
104.17 + *
104.18 + * You should have received a copy of the GNU General Public License
104.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
104.20 + */
104.21 +package info.globalcode.sql.dk.configuration;
104.22 +
104.23 +/**
104.24 + * Use for lazy-loading of the configuration.
104.25 + *
104.26 + * @author Ing. František Kučera (frantovo.cz)
104.27 + */
104.28 +public interface ConfigurationProvider {
104.29 +
104.30 + public Configuration getConfiguration() throws ConfigurationException;
104.31 +}
105.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
105.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/DatabaseDefinition.java Mon Mar 04 20:15:24 2019 +0100
105.3 @@ -0,0 +1,147 @@
105.4 +/**
105.5 + * SQL-DK
105.6 + * Copyright © 2013 František Kučera (frantovo.cz)
105.7 + *
105.8 + * This program is free software: you can redistribute it and/or modify
105.9 + * it under the terms of the GNU General Public License as published by
105.10 + * the Free Software Foundation, either version 3 of the License, or
105.11 + * (at your option) any later version.
105.12 + *
105.13 + * This program is distributed in the hope that it will be useful,
105.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
105.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105.16 + * GNU General Public License for more details.
105.17 + *
105.18 + * You should have received a copy of the GNU General Public License
105.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
105.20 + */
105.21 +package info.globalcode.sql.dk.configuration;
105.22 +
105.23 +import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
105.24 +import info.globalcode.sql.dk.DatabaseConnection;
105.25 +import info.globalcode.sql.dk.jmx.ConnectionManagement;
105.26 +import java.sql.SQLException;
105.27 +import java.util.logging.Logger;
105.28 +import javax.xml.bind.annotation.XmlElement;
105.29 +
105.30 +/**
105.31 + * Configured (but not yet connected) database connection.
105.32 + *
105.33 + * @author Ing. František Kučera (frantovo.cz)
105.34 + */
105.35 +public class DatabaseDefinition implements NameIdentified {
105.36 +
105.37 + private static final Logger log = Logger.getLogger(DatabaseDefinition.class.getName());
105.38 + /**
105.39 + * database name in SQL-DK configuration
105.40 + */
105.41 + private String name;
105.42 + /**
105.43 + * JDBC URL
105.44 + */
105.45 + private String url;
105.46 + /**
105.47 + * JDBC user name
105.48 + */
105.49 + private String userName;
105.50 + /**
105.51 + * JDBC password
105.52 + */
105.53 + private String password;
105.54 + /**
105.55 + * optional JDBC driver – if empty, the DriverManager is used to lookup specific Driver for
105.56 + * given URL
105.57 + */
105.58 + private String driver;
105.59 + /**
105.60 + * JDBC properties
105.61 + */
105.62 + private Properties properties = new Properties();
105.63 + /**
105.64 + * optional definition of tunnel to the remote database
105.65 + */
105.66 + private TunnelDefinition tunnel;
105.67 +
105.68 + @XmlElement(name = "name", namespace = CONFIGURATION)
105.69 + @Override
105.70 + public String getName() {
105.71 + return name;
105.72 + }
105.73 +
105.74 + public void setName(String name) {
105.75 + this.name = name;
105.76 + }
105.77 +
105.78 + @XmlElement(name = "url", namespace = CONFIGURATION)
105.79 + public String getUrl() {
105.80 + return url;
105.81 + }
105.82 +
105.83 + public void setUrl(String url) {
105.84 + this.url = url;
105.85 + }
105.86 +
105.87 + @XmlElement(name = "userName", namespace = CONFIGURATION)
105.88 + public String getUserName() {
105.89 + return userName;
105.90 + }
105.91 +
105.92 + public void setUserName(String userName) {
105.93 + this.userName = userName;
105.94 + }
105.95 +
105.96 + @XmlElement(name = "password", namespace = CONFIGURATION)
105.97 + public String getPassword() {
105.98 + return password;
105.99 + }
105.100 +
105.101 + public void setPassword(String password) {
105.102 + this.password = password;
105.103 + }
105.104 +
105.105 + public String getDriver() {
105.106 + return driver;
105.107 + }
105.108 +
105.109 + public void setDriver(String driver) {
105.110 + this.driver = driver;
105.111 + }
105.112 +
105.113 + @XmlElement(name = "property", namespace = CONFIGURATION)
105.114 + public Properties getProperties() {
105.115 + return properties;
105.116 + }
105.117 +
105.118 + public void setProperties(Properties properties) {
105.119 + this.properties = properties;
105.120 + }
105.121 +
105.122 + public TunnelDefinition getTunnel() {
105.123 + return tunnel;
105.124 + }
105.125 +
105.126 + public void setTunnel(TunnelDefinition tunnel) {
105.127 + this.tunnel = tunnel;
105.128 + }
105.129 +
105.130 + /**
105.131 + * @param properties ad-hoc properties from CLI options (for the JDBC driver)
105.132 + * @param jmxBean JMX management bean for progress reporting | null = disable JMX
105.133 + * @return
105.134 + * @throws java.sql.SQLException
105.135 + */
105.136 + public DatabaseConnection connect(Properties properties, ConnectionManagement jmxBean) throws SQLException {
105.137 + return new DatabaseConnection(this, properties, jmxBean);
105.138 + }
105.139 +
105.140 + /**
105.141 + * @param properties
105.142 + * @return
105.143 + * @throws java.sql.SQLException
105.144 + * @see #connect(info.globalcode.sql.dk.configuration.Properties, java.lang.String)
105.145 + * With disabled JMX reporting.
105.146 + */
105.147 + public DatabaseConnection connect(Properties properties) throws SQLException {
105.148 + return new DatabaseConnection(this, properties, null);
105.149 + }
105.150 +}
106.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
106.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/FormatterDefinition.java Mon Mar 04 20:15:24 2019 +0100
106.3 @@ -0,0 +1,114 @@
106.4 +/**
106.5 + * SQL-DK
106.6 + * Copyright © 2013 František Kučera (frantovo.cz)
106.7 + *
106.8 + * This program is free software: you can redistribute it and/or modify
106.9 + * it under the terms of the GNU General Public License as published by
106.10 + * the Free Software Foundation, either version 3 of the License, or
106.11 + * (at your option) any later version.
106.12 + *
106.13 + * This program is distributed in the hope that it will be useful,
106.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
106.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106.16 + * GNU General Public License for more details.
106.17 + *
106.18 + * You should have received a copy of the GNU General Public License
106.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
106.20 + */
106.21 +package info.globalcode.sql.dk.configuration;
106.22 +
106.23 +import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
106.24 +import info.globalcode.sql.dk.formatting.Formatter;
106.25 +import info.globalcode.sql.dk.formatting.FormatterContext;
106.26 +import info.globalcode.sql.dk.formatting.FormatterException;
106.27 +import java.lang.reflect.Constructor;
106.28 +import java.lang.reflect.InvocationTargetException;
106.29 +import javax.xml.bind.annotation.XmlElement;
106.30 +
106.31 +/**
106.32 + * Configured (but not yet instantiated) formatter.
106.33 + *
106.34 + * @author Ing. František Kučera (frantovo.cz)
106.35 + */
106.36 +public class FormatterDefinition implements NameIdentified {
106.37 +
106.38 + private String name;
106.39 + private String className;
106.40 + private Properties properties = new Properties();
106.41 +
106.42 + public FormatterDefinition() {
106.43 + }
106.44 +
106.45 + public FormatterDefinition(String name, String className) {
106.46 + this.name = name;
106.47 + this.className = className;
106.48 + }
106.49 +
106.50 + public FormatterDefinition(String name, String className, Properties properties) {
106.51 + this(name, className);
106.52 + this.properties = properties;
106.53 + }
106.54 +
106.55 + @XmlElement(name = "name", namespace = CONFIGURATION)
106.56 + @Override
106.57 + public String getName() {
106.58 + return name;
106.59 + }
106.60 +
106.61 + public void setName(String name) {
106.62 + this.name = name;
106.63 + }
106.64 +
106.65 + /**
106.66 + * Filter's class. Must implement the
106.67 + * <code>info.globalcode.sql.dk.formatting.Formatter</code> interface.
106.68 + * Subclassing the
106.69 + * <code>info.globalcode.sql.dk.formatting.AbstractFormatter</code> is strongly recommended.
106.70 + * The constructor must accept one parameter:
106.71 + * <code>info.globalcode.sql.dk.formatting.FormatterContext</code>
106.72 + *
106.73 + * @return fully qualified class name
106.74 + */
106.75 + @XmlElement(name = "class", namespace = CONFIGURATION)
106.76 + public String getClassName() {
106.77 + return className;
106.78 + }
106.79 +
106.80 + public void setClassName(String className) {
106.81 + this.className = className;
106.82 + }
106.83 +
106.84 + @XmlElement(name = "property", namespace = CONFIGURATION)
106.85 + public Properties getProperties() {
106.86 + return properties;
106.87 + }
106.88 +
106.89 + public void setProperties(Properties properties) {
106.90 + this.properties = properties;
106.91 + }
106.92 +
106.93 + /**
106.94 + * @param context
106.95 + * @return
106.96 + * @throws FormatterException
106.97 + */
106.98 + public Formatter getInstance(FormatterContext context) throws FormatterException {
106.99 + context.getProperties().setDefaults(properties);
106.100 + try {
106.101 + Constructor constructor = Class.forName(className).getConstructor(context.getClass());
106.102 +
106.103 + Object instance = constructor.newInstance(context);
106.104 + if (instance instanceof Formatter) {
106.105 + return (Formatter) instance;
106.106 + } else {
106.107 + throw new FormatterException("Formatter " + instance + " does not implement the " + Formatter.class.getName() + " interface");
106.108 + }
106.109 + } catch (ClassNotFoundException e) {
106.110 + throw new FormatterException("Formatter class does not exist: " + className, e);
106.111 + } catch (NoSuchMethodException e) {
106.112 + throw new FormatterException("Formatter class with no valid constructor: " + className, e);
106.113 + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
106.114 + throw new FormatterException("Formatter's constructor caused an error: " + className, e);
106.115 + }
106.116 + }
106.117 +}
107.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
107.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/Loader.java Mon Mar 04 20:15:24 2019 +0100
107.3 @@ -0,0 +1,101 @@
107.4 +/**
107.5 + * SQL-DK
107.6 + * Copyright © 2015 František Kučera (frantovo.cz)
107.7 + *
107.8 + * This program is free software: you can redistribute it and/or modify
107.9 + * it under the terms of the GNU General Public License as published by
107.10 + * the Free Software Foundation, either version 3 of the License, or
107.11 + * (at your option) any later version.
107.12 + *
107.13 + * This program is distributed in the hope that it will be useful,
107.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
107.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
107.16 + * GNU General Public License for more details.
107.17 + *
107.18 + * You should have received a copy of the GNU General Public License
107.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
107.20 + */
107.21 +package info.globalcode.sql.dk.configuration;
107.22 +
107.23 +import info.globalcode.sql.dk.*;
107.24 +import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_USER;
107.25 +import static info.globalcode.sql.dk.DatabaseConnection.JDBC_PROPERTY_PASSWORD;
107.26 +import java.sql.Connection;
107.27 +import java.sql.Driver;
107.28 +import java.sql.DriverManager;
107.29 +import java.sql.SQLException;
107.30 +import java.util.logging.Level;
107.31 +import java.util.logging.Logger;
107.32 +import javax.xml.bind.JAXBContext;
107.33 +import javax.xml.bind.Unmarshaller;
107.34 +
107.35 +/**
107.36 + * Configuration loader – deserializes Configuration from the XML file.
107.37 + *
107.38 + * @author Ing. František Kučera (frantovo.cz)
107.39 + */
107.40 +public class Loader {
107.41 +
107.42 + private static final Logger log = Logger.getLogger(Loader.class.getName());
107.43 +
107.44 + public Configuration loadConfiguration() throws ConfigurationException {
107.45 + try {
107.46 + JAXBContext jaxb = JAXBContext.newInstance(Configuration.class.getPackage().getName(), Configuration.class.getClassLoader());
107.47 + Unmarshaller u = jaxb.createUnmarshaller();
107.48 + return (Configuration) u.unmarshal(Constants.CONFIG_FILE);
107.49 + } catch (Exception e) {
107.50 + throw new ConfigurationException("Unable to load configuration from " + Constants.CONFIG_FILE, e);
107.51 + }
107.52 + }
107.53 +
107.54 + /**
107.55 + * JDBC connection should not be used directly in SQL-DK.
107.56 + *
107.57 + * @see DatabaseDefinition#connect(info.globalcode.sql.dk.configuration.Properties)
107.58 + * @param properties
107.59 + * @param databaseDefinition
107.60 + * @return
107.61 + * @throws java.sql.SQLException
107.62 + */
107.63 + public static Connection jdbcConnect(DatabaseDefinition databaseDefinition, Properties properties) throws SQLException {
107.64 + synchronized (properties) {
107.65 + /**
107.66 + * Avoid rewriting the properties. Usually, the connection is created only once, but
107.67 + * with --test-connection and with SQL-DK JDBC driver, it might be reused.
107.68 + */
107.69 + properties = properties.clone();
107.70 + }
107.71 + if (properties.hasProperty(JDBC_PROPERTY_PASSWORD)) {
107.72 + log.log(Level.WARNING, "Passing DB password as CLI parameter is insecure!");
107.73 + }
107.74 + Properties credentials = new Properties();
107.75 + credentials.add(new Property(JDBC_PROPERTY_USER, databaseDefinition.getUserName()));
107.76 + credentials.add(new Property(JDBC_PROPERTY_PASSWORD, databaseDefinition.getPassword()));
107.77 + credentials.setDefaults(databaseDefinition.getProperties());
107.78 + properties.setDefaults(credentials);
107.79 + java.util.Properties javaProperties = properties.getJavaProperties();
107.80 +
107.81 + String driverClassName = databaseDefinition.getDriver();
107.82 + final String url = databaseDefinition.getUrl();
107.83 + if (driverClassName == null) {
107.84 + log.log(Level.FINE, "Using DriverManager to create connection for „{0}“", url);
107.85 + return DriverManager.getConnection(url, javaProperties);
107.86 + } else {
107.87 + log.log(Level.FINE, "Using custom Driver „{0}“ to create connection for „{1}“", new Object[]{driverClassName, url});
107.88 + try {
107.89 + Class<Driver> driverClass = (Class<Driver>) Class.forName(driverClassName);
107.90 + Driver driver = driverClass.newInstance();
107.91 + Connection connection = driver.connect(url, javaProperties);
107.92 + if (connection == null) {
107.93 + log.log(Level.SEVERE, "Driver „{0}“ returend null → it does not accept the URL: „{1}“", new Object[]{driverClassName, url});
107.94 + throw new SQLException("Unable to connect: driver returned null.");
107.95 + } else {
107.96 + return connection;
107.97 + }
107.98 + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException e) {
107.99 + throw new SQLException("Unable to connect usig specific driver: " + driverClassName, e);
107.100 + }
107.101 + }
107.102 + }
107.103 +
107.104 +}
108.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
108.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/NameIdentified.java Mon Mar 04 20:15:24 2019 +0100
108.3 @@ -0,0 +1,27 @@
108.4 +/**
108.5 + * SQL-DK
108.6 + * Copyright © 2013 František Kučera (frantovo.cz)
108.7 + *
108.8 + * This program is free software: you can redistribute it and/or modify
108.9 + * it under the terms of the GNU General Public License as published by
108.10 + * the Free Software Foundation, either version 3 of the License, or
108.11 + * (at your option) any later version.
108.12 + *
108.13 + * This program is distributed in the hope that it will be useful,
108.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
108.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
108.16 + * GNU General Public License for more details.
108.17 + *
108.18 + * You should have received a copy of the GNU General Public License
108.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
108.20 + */
108.21 +package info.globalcode.sql.dk.configuration;
108.22 +
108.23 +/**
108.24 + *
108.25 + * @author Ing. František Kučera (frantovo.cz)
108.26 + */
108.27 +public interface NameIdentified {
108.28 +
108.29 + public String getName();
108.30 +}
109.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
109.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/Properties.java Mon Mar 04 20:15:24 2019 +0100
109.3 @@ -0,0 +1,129 @@
109.4 +/**
109.5 + * SQL-DK
109.6 + * Copyright © 2013 František Kučera (frantovo.cz)
109.7 + *
109.8 + * This program is free software: you can redistribute it and/or modify
109.9 + * it under the terms of the GNU General Public License as published by
109.10 + * the Free Software Foundation, either version 3 of the License, or
109.11 + * (at your option) any later version.
109.12 + *
109.13 + * This program is distributed in the hope that it will be useful,
109.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
109.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
109.16 + * GNU General Public License for more details.
109.17 + *
109.18 + * You should have received a copy of the GNU General Public License
109.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
109.20 + */
109.21 +package info.globalcode.sql.dk.configuration;
109.22 +
109.23 +import java.util.ArrayList;
109.24 +import javax.xml.bind.annotation.XmlTransient;
109.25 +import static info.globalcode.sql.dk.Functions.findByName;
109.26 +import java.util.Collections;
109.27 +
109.28 +/**
109.29 + * <p>
109.30 + * List of configurables.</p>
109.31 + *
109.32 + * <p>
109.33 + * Can be backed by defaults – if value for given name is nof found in this instance, we will
109.34 + * look into defaults. Methods also accept defaultValue parameter – is used if property is nof found
109.35 + * even in default properties.</p>
109.36 + *
109.37 + * <p>
109.38 + * Typical use: </p>
109.39 + * <ul>
109.40 + * <li>this instance – ad-hoc properties from CLI options</li>
109.41 + * <li>default properties – from config file</li>
109.42 + * <li>defaultValue – hardcoded default</li>
109.43 + * </ul>
109.44 + *
109.45 + * @author Ing. František Kučera (frantovo.cz)
109.46 + */
109.47 +public class Properties extends ArrayList<Property> implements Cloneable {
109.48 +
109.49 + private Properties defaults;
109.50 +
109.51 + public Properties() {
109.52 + }
109.53 +
109.54 + public Properties(int initialCapacity) {
109.55 + super(initialCapacity);
109.56 + }
109.57 +
109.58 + @XmlTransient
109.59 + public Properties getDefaults() {
109.60 + return defaults;
109.61 + }
109.62 +
109.63 + public void setDefaults(Properties defaults) {
109.64 + this.defaults = defaults;
109.65 + }
109.66 +
109.67 + /**
109.68 + * @param defaults the last/deepest defaults
109.69 + */
109.70 + public void setLastDefaults(Properties defaults) {
109.71 + if (this.defaults == null) {
109.72 + this.defaults = defaults;
109.73 + } else {
109.74 + this.defaults.setLastDefaults(defaults);
109.75 + }
109.76 + }
109.77 +
109.78 + private Property findProperty(String name) {
109.79 + Property p = findByName(this, name);
109.80 + if (p == null && defaults != null) {
109.81 + p = defaults.findProperty(name);
109.82 + }
109.83 + return p;
109.84 + }
109.85 +
109.86 + public String getString(String name, String defaultValue) {
109.87 + Property p = findProperty(name);
109.88 + return p == null ? defaultValue : p.getValue();
109.89 + }
109.90 +
109.91 + public boolean getBoolean(String name, boolean defaultValue) {
109.92 + Property p = findProperty(name);
109.93 + return p == null ? defaultValue : Boolean.valueOf(p.getValue());
109.94 + }
109.95 +
109.96 + public int getInteger(String name, int defaultValue) {
109.97 + Property p = findProperty(name);
109.98 + return p == null ? defaultValue : Integer.valueOf(p.getValue());
109.99 + }
109.100 +
109.101 + public boolean hasProperty(String name) {
109.102 + return findByName(this, name) != null;
109.103 + }
109.104 +
109.105 + @Override
109.106 + public Properties clone() {
109.107 + Properties clone = new Properties(size());
109.108 + Collections.copy(clone, this);
109.109 + return clone;
109.110 + }
109.111 +
109.112 + /**
109.113 + * @return merged this and backing defaults as Java Properties
109.114 + */
109.115 + public java.util.Properties getJavaProperties() {
109.116 + java.util.Properties javaProperties = new java.util.Properties();
109.117 + duplicateTo(javaProperties);
109.118 + return javaProperties;
109.119 + }
109.120 +
109.121 + private void duplicateTo(java.util.Properties javaProperties) {
109.122 + if (defaults != null) {
109.123 + defaults.duplicateTo(javaProperties);
109.124 + }
109.125 + for (Property p : this) {
109.126 + String value = p.getValue();
109.127 + if (value != null) {
109.128 + javaProperties.setProperty(p.getName(), value);
109.129 + }
109.130 + }
109.131 + }
109.132 +}
110.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
110.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/Property.java Mon Mar 04 20:15:24 2019 +0100
110.3 @@ -0,0 +1,69 @@
110.4 +/**
110.5 + * SQL-DK
110.6 + * Copyright © 2013 František Kučera (frantovo.cz)
110.7 + *
110.8 + * This program is free software: you can redistribute it and/or modify
110.9 + * it under the terms of the GNU General Public License as published by
110.10 + * the Free Software Foundation, either version 3 of the License, or
110.11 + * (at your option) any later version.
110.12 + *
110.13 + * This program is distributed in the hope that it will be useful,
110.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
110.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110.16 + * GNU General Public License for more details.
110.17 + *
110.18 + * You should have received a copy of the GNU General Public License
110.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
110.20 + */
110.21 +package info.globalcode.sql.dk.configuration;
110.22 +
110.23 +import javax.xml.bind.annotation.XmlAttribute;
110.24 +import javax.xml.bind.annotation.XmlValue;
110.25 +
110.26 +/**
110.27 + * One configurable
110.28 + *
110.29 + * @author Ing. František Kučera (frantovo.cz)
110.30 + */
110.31 +public class Property implements NameIdentified, Cloneable {
110.32 +
110.33 + private String name;
110.34 + private String value;
110.35 +
110.36 + public Property() {
110.37 + }
110.38 +
110.39 + public Property(String name, String value) {
110.40 + this.name = name;
110.41 + this.value = value;
110.42 + }
110.43 +
110.44 + @XmlAttribute(name = "name")
110.45 + @Override
110.46 + public String getName() {
110.47 + return name;
110.48 + }
110.49 +
110.50 + public void setName(String name) {
110.51 + this.name = name;
110.52 + }
110.53 +
110.54 + @XmlValue
110.55 + public String getValue() {
110.56 + return value;
110.57 + }
110.58 +
110.59 + public void setValue(String value) {
110.60 + this.value = value;
110.61 + }
110.62 +
110.63 + @Override
110.64 + public String toString() {
110.65 + return name + "='" + value + "'";
110.66 + }
110.67 +
110.68 + @Override
110.69 + protected Property clone() {
110.70 + return new Property(name, value);
110.71 + }
110.72 +}
111.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
111.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/PropertyDeclaration.java Mon Mar 04 20:15:24 2019 +0100
111.3 @@ -0,0 +1,57 @@
111.4 +/**
111.5 + * SQL-DK
111.6 + * Copyright © 2015 František Kučera (frantovo.cz)
111.7 + *
111.8 + * This program is free software: you can redistribute it and/or modify
111.9 + * it under the terms of the GNU General Public License as published by
111.10 + * the Free Software Foundation, either version 3 of the License, or
111.11 + * (at your option) any later version.
111.12 + *
111.13 + * This program is distributed in the hope that it will be useful,
111.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
111.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111.16 + * GNU General Public License for more details.
111.17 + *
111.18 + * You should have received a copy of the GNU General Public License
111.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
111.20 + */
111.21 +package info.globalcode.sql.dk.configuration;
111.22 +
111.23 +import java.lang.annotation.ElementType;
111.24 +import java.lang.annotation.Repeatable;
111.25 +import java.lang.annotation.Retention;
111.26 +import static java.lang.annotation.RetentionPolicy.RUNTIME;
111.27 +import java.lang.annotation.Target;
111.28 +
111.29 +/**
111.30 + * Declaration of the (formatter) properties – for documentation purposes.
111.31 + *
111.32 + * TODO: automatically inject properties (configured, ad-hoc, default ones) to the formatters
111.33 + *
111.34 + * @author Ing. František Kučera (frantovo.cz)
111.35 + */
111.36 +@Retention(RUNTIME)
111.37 +@Target({ElementType.TYPE})
111.38 +@Repeatable(PropertyDeclarations.class)
111.39 +public @interface PropertyDeclaration {
111.40 +
111.41 + /**
111.42 + * @return name of the property
111.43 + */
111.44 + String name();
111.45 +
111.46 + /**
111.47 + * @return data type of the value: String, numbers, Boolean or Enum
111.48 + */
111.49 + Class type();
111.50 +
111.51 + /**
111.52 + * @return documentation for the users
111.53 + */
111.54 + String description();
111.55 +
111.56 + /**
111.57 + * @return default value of this property
111.58 + */
111.59 + String defaultValue();
111.60 +}
112.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
112.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/PropertyDeclarations.java Mon Mar 04 20:15:24 2019 +0100
112.3 @@ -0,0 +1,35 @@
112.4 +/**
112.5 + * SQL-DK
112.6 + * Copyright © 2015 František Kučera (frantovo.cz)
112.7 + *
112.8 + * This program is free software: you can redistribute it and/or modify
112.9 + * it under the terms of the GNU General Public License as published by
112.10 + * the Free Software Foundation, either version 3 of the License, or
112.11 + * (at your option) any later version.
112.12 + *
112.13 + * This program is distributed in the hope that it will be useful,
112.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
112.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
112.16 + * GNU General Public License for more details.
112.17 + *
112.18 + * You should have received a copy of the GNU General Public License
112.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
112.20 + */
112.21 +package info.globalcode.sql.dk.configuration;
112.22 +
112.23 +import java.lang.annotation.ElementType;
112.24 +import java.lang.annotation.Retention;
112.25 +import static java.lang.annotation.RetentionPolicy.RUNTIME;
112.26 +import java.lang.annotation.Target;
112.27 +
112.28 +/**
112.29 + *
112.30 + * @author Ing. František Kučera (frantovo.cz)
112.31 + */
112.32 +@Retention(RUNTIME)
112.33 +@Target({ElementType.TYPE})
112.34 +public @interface PropertyDeclarations {
112.35 +
112.36 + PropertyDeclaration[] value();
112.37 +
112.38 +}
113.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
113.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/configuration/TunnelDefinition.java Mon Mar 04 20:15:24 2019 +0100
113.3 @@ -0,0 +1,51 @@
113.4 +/**
113.5 + * SQL-DK
113.6 + * Copyright © 2015 František Kučera (frantovo.cz)
113.7 + *
113.8 + * This program is free software: you can redistribute it and/or modify
113.9 + * it under the terms of the GNU General Public License as published by
113.10 + * the Free Software Foundation, either version 3 of the License, or
113.11 + * (at your option) any later version.
113.12 + *
113.13 + * This program is distributed in the hope that it will be useful,
113.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
113.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
113.16 + * GNU General Public License for more details.
113.17 + *
113.18 + * You should have received a copy of the GNU General Public License
113.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
113.20 + */
113.21 +package info.globalcode.sql.dk.configuration;
113.22 +
113.23 +import static info.globalcode.sql.dk.Xmlns.CONFIGURATION;
113.24 +import java.util.List;
113.25 +import javax.xml.bind.annotation.XmlElement;
113.26 +
113.27 +/**
113.28 + *
113.29 + * @author Ing. František Kučera (frantovo.cz)
113.30 + */
113.31 +public class TunnelDefinition {
113.32 +
113.33 + private String command;
113.34 + private List<CommandArgument> arguments;
113.35 +
113.36 + @XmlElement(name = "command", namespace = CONFIGURATION)
113.37 + public String getCommand() {
113.38 + return command;
113.39 + }
113.40 +
113.41 + public void setCommand(String command) {
113.42 + this.command = command;
113.43 + }
113.44 +
113.45 + @XmlElement(name = "argument", namespace = CONFIGURATION)
113.46 + public List<CommandArgument> getArguments() {
113.47 + return arguments;
113.48 + }
113.49 +
113.50 + public void setArguments(List<CommandArgument> arguments) {
113.51 + this.arguments = arguments;
113.52 + }
113.53 +
113.54 +}
114.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
114.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/AbstractFormatter.java Mon Mar 04 20:15:24 2019 +0100
114.3 @@ -0,0 +1,254 @@
114.4 +/**
114.5 + * SQL-DK
114.6 + * Copyright © 2013 František Kučera (frantovo.cz)
114.7 + *
114.8 + * This program is free software: you can redistribute it and/or modify
114.9 + * it under the terms of the GNU General Public License as published by
114.10 + * the Free Software Foundation, either version 3 of the License, or
114.11 + * (at your option) any later version.
114.12 + *
114.13 + * This program is distributed in the hope that it will be useful,
114.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
114.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
114.16 + * GNU General Public License for more details.
114.17 + *
114.18 + * You should have received a copy of the GNU General Public License
114.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
114.20 + */
114.21 +package info.globalcode.sql.dk.formatting;
114.22 +
114.23 +import info.globalcode.sql.dk.Parameter;
114.24 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
114.25 +import java.util.EmptyStackException;
114.26 +import java.util.EnumSet;
114.27 +import java.util.List;
114.28 +import java.util.Stack;
114.29 +
114.30 +/**
114.31 + * <ol>
114.32 + * <li>ensures integrity – if methods are called in correct order and context</li>
114.33 + * <li>provides default implmentations of methods that does not produce any output for given
114.34 + * events</li>
114.35 + * </ol>
114.36 + *
114.37 + * @author Ing. František Kučera (frantovo.cz)
114.38 + */
114.39 +public abstract class AbstractFormatter implements Formatter {
114.40 +
114.41 + private Stack<State> state = new Stack<>();
114.42 + private FormatterContext formatterContext;
114.43 + private ColumnsHeader currentColumnsHeader;
114.44 + private String currentQuery;
114.45 + private int currentColumnsCount;
114.46 + private int currentRowCount;
114.47 +
114.48 + public AbstractFormatter(FormatterContext formatterContext) {
114.49 + this.formatterContext = formatterContext;
114.50 + state.push(State.ROOT);
114.51 + }
114.52 +
114.53 + /*
114.54 + * root
114.55 + * .batch
114.56 + * ..database
114.57 + * ...statement
114.58 + * ....@query
114.59 + * ....@parameters
114.60 + * ....resultSet
114.61 + * .....row
114.62 + * ......@columnValue
114.63 + * ....@updatesResult
114.64 + */
114.65 + protected enum State {
114.66 +
114.67 + ROOT,
114.68 + BATCH,
114.69 + DATABASE,
114.70 + STATEMENT,
114.71 + RESULT_SET,
114.72 + ROW
114.73 + }
114.74 +
114.75 + /**
114.76 + * Go down in hierarchy.
114.77 + * Pushes new state and verifies the old one.
114.78 + *
114.79 + * @param current the new state – currently entering
114.80 + * @param expected expected previous states (any of them is valid)
114.81 + * @return previous state
114.82 + * @throws IllegalStateException if previous state was not one from expected
114.83 + */
114.84 + private State pushState(State current, EnumSet expected) {
114.85 + State previous = state.peek();
114.86 +
114.87 + if (expected.contains(previous)) {
114.88 + state.push(current);
114.89 + return previous;
114.90 + } else {
114.91 + throw new IllegalStateException("Formatter was in wrong state: " + previous + " when it should be in one of: " + expected);
114.92 + }
114.93 + }
114.94 +
114.95 + protected State peekState(EnumSet expected) {
114.96 + State current = state.peek();
114.97 +
114.98 + if (expected.contains(current)) {
114.99 + return current;
114.100 + } else {
114.101 + throw new IllegalStateException("Formatter is in wrong state: " + current + " when it should be in one of: " + expected);
114.102 + }
114.103 +
114.104 + }
114.105 +
114.106 + /**
114.107 + * Go up in hierarchy.
114.108 + * Pops the superior state/branch.
114.109 + *
114.110 + * @param expected expected superior state
114.111 + * @return the superior state
114.112 + * @throws IllegalStateException if superior state was not one from expected or if there is no
114.113 + * more superior state (we are at root level)
114.114 + */
114.115 + private State popState(EnumSet expected) {
114.116 + try {
114.117 + state.pop();
114.118 + State superior = state.peek();
114.119 + if (expected.contains(superior)) {
114.120 + return superior;
114.121 + } else {
114.122 + throw new IllegalStateException("Formatter had wrong superior state: " + superior + " when it should be in one of: " + expected);
114.123 + }
114.124 + } catch (EmptyStackException e) {
114.125 + throw new IllegalStateException("Formatter was already at root level – there is nothing above that.", e);
114.126 + }
114.127 + }
114.128 +
114.129 + @Override
114.130 + public void writeStartBatch() {
114.131 + pushState(State.BATCH, EnumSet.of(State.ROOT));
114.132 + }
114.133 +
114.134 + @Override
114.135 + public void writeEndBatch() {
114.136 + popState(EnumSet.of(State.ROOT));
114.137 + }
114.138 +
114.139 + @Override
114.140 + public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
114.141 + pushState(State.DATABASE, EnumSet.of(State.BATCH));
114.142 + }
114.143 +
114.144 + @Override
114.145 + public void writeEndDatabase() {
114.146 + popState(EnumSet.of(State.BATCH));
114.147 + }
114.148 +
114.149 + @Override
114.150 + public void writeStartStatement() {
114.151 + pushState(State.STATEMENT, EnumSet.of(State.DATABASE));
114.152 + }
114.153 +
114.154 + @Override
114.155 + public void writeEndStatement() {
114.156 + popState(EnumSet.of(State.DATABASE));
114.157 + }
114.158 +
114.159 + @Override
114.160 + public void writeStartResultSet(ColumnsHeader header) {
114.161 + pushState(State.RESULT_SET, EnumSet.of(State.STATEMENT));
114.162 + currentRowCount = 0;
114.163 + currentColumnsHeader = header;
114.164 + }
114.165 +
114.166 + @Override
114.167 + public void writeEndResultSet() {
114.168 + popState(EnumSet.of(State.STATEMENT));
114.169 + currentColumnsHeader = null;
114.170 + }
114.171 +
114.172 + @Override
114.173 + public void writeQuery(String sql) {
114.174 + peekState(EnumSet.of(State.STATEMENT));
114.175 +
114.176 + if (currentColumnsHeader == null) {
114.177 + currentQuery = sql;
114.178 + } else {
114.179 + throw new IllegalStateException("Query string '" + sql + "' must be set before columns header – was already set: " + currentColumnsHeader);
114.180 + }
114.181 + }
114.182 +
114.183 + @Override
114.184 + public void writeParameters(List<? extends Parameter> parameters) {
114.185 + peekState(EnumSet.of(State.STATEMENT));
114.186 +
114.187 + if (currentColumnsHeader != null) {
114.188 + throw new IllegalStateException("Parameters '" + parameters + "' must be set before columns header – was already set: " + currentColumnsHeader);
114.189 + }
114.190 +
114.191 + if (currentQuery == null && parameters != null) {
114.192 + throw new IllegalStateException("Parameters '" + parameters + "' must be set after query – was not yet set.");
114.193 + }
114.194 + }
114.195 +
114.196 + @Override
114.197 + public void writeStartRow() {
114.198 + pushState(State.ROW, EnumSet.of(State.RESULT_SET));
114.199 + currentColumnsCount = 0;
114.200 + currentRowCount++;
114.201 + }
114.202 +
114.203 + @Override
114.204 + public void writeEndRow() {
114.205 + popState(EnumSet.of(State.RESULT_SET));
114.206 + }
114.207 +
114.208 + @Override
114.209 + public void writeColumnValue(Object value) {
114.210 + peekState(EnumSet.of(State.ROW));
114.211 + currentColumnsCount++;
114.212 +
114.213 + int declaredCount = currentColumnsHeader.getColumnCount();
114.214 + if (currentColumnsCount > declaredCount) {
114.215 + throw new IllegalStateException("Current columns count is " + currentColumnsCount + " which is more than declared " + declaredCount + " in header.");
114.216 + }
114.217 + }
114.218 +
114.219 + @Override
114.220 + public void writeUpdatesResult(int updatedRowsCount) {
114.221 + peekState(EnumSet.of(State.STATEMENT));
114.222 + }
114.223 +
114.224 + @Override
114.225 + public void close() throws FormatterException {
114.226 + }
114.227 +
114.228 + public FormatterContext getFormatterContext() {
114.229 + return formatterContext;
114.230 + }
114.231 +
114.232 + protected ColumnsHeader getCurrentColumnsHeader() {
114.233 + return currentColumnsHeader;
114.234 + }
114.235 +
114.236 + /**
114.237 + * @return column number, 1 = first
114.238 + */
114.239 + protected int getCurrentColumnsCount() {
114.240 + return currentColumnsCount;
114.241 + }
114.242 +
114.243 + protected boolean isCurrentColumnFirst() {
114.244 + return currentColumnsCount == 1;
114.245 + }
114.246 +
114.247 + protected boolean isCurrentColumnLast() {
114.248 + return currentColumnsCount == currentColumnsHeader.getColumnCount();
114.249 + }
114.250 +
114.251 + /**
114.252 + * @return row number, 1 = first
114.253 + */
114.254 + protected int getCurrentRowCount() {
114.255 + return currentRowCount;
114.256 + }
114.257 +}
115.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
115.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/AbstractXmlFormatter.java Mon Mar 04 20:15:24 2019 +0100
115.3 @@ -0,0 +1,241 @@
115.4 +/**
115.5 + * SQL-DK
115.6 + * Copyright © 2014 František Kučera (frantovo.cz)
115.7 + *
115.8 + * This program is free software: you can redistribute it and/or modify
115.9 + * it under the terms of the GNU General Public License as published by
115.10 + * the Free Software Foundation, either version 3 of the License, or
115.11 + * (at your option) any later version.
115.12 + *
115.13 + * This program is distributed in the hope that it will be useful,
115.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
115.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
115.16 + * GNU General Public License for more details.
115.17 + *
115.18 + * You should have received a copy of the GNU General Public License
115.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
115.20 + */
115.21 +package info.globalcode.sql.dk.formatting;
115.22 +
115.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
115.24 +import info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
115.25 +import java.util.Stack;
115.26 +import javax.xml.namespace.QName;
115.27 +import static info.globalcode.sql.dk.Functions.isEmpty;
115.28 +import static info.globalcode.sql.dk.Functions.toHex;
115.29 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
115.30 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
115.31 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
115.32 +import java.nio.charset.Charset;
115.33 +import java.util.EmptyStackException;
115.34 +import java.util.HashMap;
115.35 +import java.util.LinkedHashMap;
115.36 +import java.util.Map;
115.37 +import java.util.Map.Entry;
115.38 +import java.util.logging.Level;
115.39 +import java.util.logging.Logger;
115.40 +
115.41 +/**
115.42 + * <p>
115.43 + * Provides helper methods for printing pretty intended and optionally colorful (syntax highlighted)
115.44 + * XML output.
115.45 + * </p>
115.46 + *
115.47 + * <p>
115.48 + * Must be used with care – bad usage can lead to invalid XML (e.g. using undeclared namespaces).
115.49 + * </p>
115.50 + *
115.51 + * @author Ing. František Kučera (frantovo.cz)
115.52 + */
115.53 +@PropertyDeclaration(name = COLORFUL, defaultValue = "false", type = Boolean.class, description = COLORFUL_DESCRIPTION)
115.54 +@PropertyDeclaration(name = AbstractXmlFormatter.PROPERTY_INDENT, defaultValue = AbstractXmlFormatter.PROPERTY_INDENT_DEFAULT, type = String.class, description = "tab or sequence of spaces used for indentation of nested elements")
115.55 +@PropertyDeclaration(name = AbstractXmlFormatter.PROPERTY_INDENT_TEXT, defaultValue = "true", type = Boolean.class, description = "whether text with line breaks should be indented; if not original whitespace will be preserved.")
115.56 +public abstract class AbstractXmlFormatter extends AbstractFormatter {
115.57 +
115.58 + private static final Logger log = Logger.getLogger(AbstractXmlFormatter.class.getName());
115.59 + public static final String PROPERTY_INDENT = "indent";
115.60 + protected static final String PROPERTY_INDENT_DEFAULT = "\t";
115.61 + public static final String PROPERTY_INDENT_TEXT = "indentText";
115.62 + private static final TerminalColor ELEMENT_COLOR = TerminalColor.Magenta;
115.63 + private static final TerminalColor ATTRIBUTE_NAME_COLOR = TerminalColor.Green;
115.64 + private static final TerminalColor ATTRIBUTE_VALUE_COLOR = TerminalColor.Yellow;
115.65 + private static final TerminalColor XML_DECLARATION_COLOR = TerminalColor.Red;
115.66 + private static final TerminalColor XML_DOCTYPE_COLOR = TerminalColor.Cyan;
115.67 + private Stack<QName> treePosition = new Stack<>();
115.68 + private final ColorfulPrintWriter out;
115.69 + private final String indent;
115.70 + private final boolean indentText;
115.71 +
115.72 + public AbstractXmlFormatter(FormatterContext formatterContext) {
115.73 + super(formatterContext);
115.74 + boolean colorful = formatterContext.getProperties().getBoolean(COLORFUL, false);
115.75 + out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
115.76 + indent = formatterContext.getProperties().getString(PROPERTY_INDENT, PROPERTY_INDENT_DEFAULT);
115.77 + indentText = formatterContext.getProperties().getBoolean(PROPERTY_INDENT_TEXT, true);
115.78 +
115.79 + if (!indent.matches("\\s*")) {
115.80 + log.log(Level.WARNING, "Setting indent to „{0}“ is weird & freaky; in hex: {1}", new Object[]{indent, toHex(indent.getBytes())});
115.81 + }
115.82 +
115.83 + }
115.84 +
115.85 + protected void printStartDocument() {
115.86 + out.print(XML_DECLARATION_COLOR, "<?xml version=\"1.0\" encoding=\"" + Charset.defaultCharset().name() + "\"?>");
115.87 + }
115.88 +
115.89 + protected void printDoctype(String doctype) {
115.90 + out.print(XML_DOCTYPE_COLOR, "\n<!DOCTYPE " + doctype + ">");
115.91 + }
115.92 +
115.93 + protected void printEndDocument() {
115.94 + out.println();
115.95 + out.flush();
115.96 + if (!treePosition.empty()) {
115.97 + throw new IllegalStateException("Some elements are not closed: " + treePosition);
115.98 + }
115.99 + }
115.100 +
115.101 + protected void printStartElement(QName element) {
115.102 + printStartElement(element, null);
115.103 + }
115.104 +
115.105 + protected Map<QName, String> singleAttribute(QName name, String value) {
115.106 + Map<QName, String> attributes = new HashMap<>(2);
115.107 + attributes.put(name, value);
115.108 + return attributes;
115.109 + }
115.110 +
115.111 + protected void printStartElement(QName element, Map<QName, String> attributes) {
115.112 + printStartElement(element, attributes, false);
115.113 + }
115.114 +
115.115 + /**
115.116 + * @param empty whether element should be closed <codfe>… /></code> (has no content, do not
115.117 + * call {@linkplain #printEndElement()})
115.118 + */
115.119 + private void printStartElement(QName element, Map<QName, String> attributes, boolean empty) {
115.120 + printIndent();
115.121 +
115.122 + out.print(ELEMENT_COLOR, "<" + toString(element));
115.123 +
115.124 + if (attributes != null) {
115.125 + for (Entry<QName, String> attribute : attributes.entrySet()) {
115.126 + out.print(" ");
115.127 + out.print(ATTRIBUTE_NAME_COLOR, toString(attribute.getKey()));
115.128 + out.print("=");
115.129 + out.print(ATTRIBUTE_VALUE_COLOR, '"' + escapeXmlAttribute(attribute.getValue()) + '"');
115.130 + }
115.131 + }
115.132 +
115.133 + if (empty) {
115.134 + out.print(ELEMENT_COLOR, "/>");
115.135 + } else {
115.136 + out.print(ELEMENT_COLOR, ">");
115.137 + treePosition.add(element);
115.138 + }
115.139 +
115.140 + out.flush();
115.141 + }
115.142 +
115.143 + /**
115.144 + * Prints text node wrapped in given element without indenting the text and adding line breaks
115.145 + * (useful for short texts).
115.146 + *
115.147 + * @param attributes use {@linkplain LinkedHashMap} to preserve attributes order
115.148 + */
115.149 + protected void printTextElement(QName element, Map<QName, String> attributes, String text) {
115.150 + printStartElement(element, attributes);
115.151 +
115.152 + String[] lines = text.split("\\n");
115.153 +
115.154 + if (indentText && lines.length > 1) {
115.155 + for (String line : lines) {
115.156 + printText(line, true);
115.157 + }
115.158 + printEndElement(true);
115.159 + } else {
115.160 + /*
115.161 + * line breaks at the end of the text will be eaten – if you need them, use indentText = false
115.162 + */
115.163 + if (lines.length == 1 && text.endsWith("\n")) {
115.164 + text = text.substring(0, text.length() - 1);
115.165 + }
115.166 +
115.167 + printText(text, false);
115.168 + printEndElement(false);
115.169 + }
115.170 + }
115.171 +
115.172 + protected void printEmptyElement(QName element, Map<QName, String> attributes) {
115.173 + printStartElement(element, attributes, true);
115.174 + }
115.175 +
115.176 + protected void printEndElement() {
115.177 + printEndElement(true);
115.178 + }
115.179 +
115.180 + private void printEndElement(boolean indent) {
115.181 + try {
115.182 + QName name = treePosition.pop();
115.183 +
115.184 + if (indent) {
115.185 + printIndent();
115.186 + }
115.187 +
115.188 + out.print(ELEMENT_COLOR, "</" + toString(name) + ">");
115.189 + out.flush();
115.190 +
115.191 + } catch (EmptyStackException e) {
115.192 + throw new IllegalStateException("No more elements to end.", e);
115.193 + }
115.194 + }
115.195 +
115.196 + protected void printText(String s, boolean indent) {
115.197 + if (indent) {
115.198 + printIndent();
115.199 + }
115.200 + out.print(escapeXmlText(s));
115.201 + out.flush();
115.202 + }
115.203 +
115.204 + protected void printIndent() {
115.205 + out.println();
115.206 + for (int i = 0; i < treePosition.size(); i++) {
115.207 + out.print(indent);
115.208 + }
115.209 + }
115.210 +
115.211 + protected static QName qname(String name) {
115.212 + return new QName(name);
115.213 + }
115.214 +
115.215 + protected static QName qname(String prefix, String name) {
115.216 + return new QName(null, name, prefix);
115.217 + }
115.218 +
115.219 + private String toString(QName name) {
115.220 + if (isEmpty(name.getPrefix(), true)) {
115.221 + return escapeName(name.getLocalPart());
115.222 + } else {
115.223 + return escapeName(name.getPrefix()) + ":" + escapeName(name.getLocalPart());
115.224 + }
115.225 + }
115.226 +
115.227 + private String escapeName(String s) {
115.228 + // TODO: avoid ugly values in <name name="…"/>
115.229 + return s;
115.230 + }
115.231 +
115.232 + private static String escapeXmlText(String s) {
115.233 + return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
115.234 + // Not needed:
115.235 + // return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
115.236 + }
115.237 +
115.238 + /**
115.239 + * Expects attribute values enclosed in "quotes" not 'apostrophes'.
115.240 + */
115.241 + private static String escapeXmlAttribute(String s) {
115.242 + return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
115.243 + }
115.244 +}
116.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
116.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/BarChartFormatter.java Mon Mar 04 20:15:24 2019 +0100
116.3 @@ -0,0 +1,104 @@
116.4 +/**
116.5 + * SQL-DK
116.6 + * Copyright © 2015 František Kučera (frantovo.cz)
116.7 + *
116.8 + * This program is free software: you can redistribute it and/or modify
116.9 + * it under the terms of the GNU General Public License as published by
116.10 + * the Free Software Foundation, either version 3 of the License, or
116.11 + * (at your option) any later version.
116.12 + *
116.13 + * This program is distributed in the hope that it will be useful,
116.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
116.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
116.16 + * GNU General Public License for more details.
116.17 + *
116.18 + * You should have received a copy of the GNU General Public License
116.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
116.20 + */
116.21 +package info.globalcode.sql.dk.formatting;
116.22 +
116.23 +import info.globalcode.sql.dk.Functions;
116.24 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
116.25 +import info.globalcode.sql.dk.logging.LoggerProducer;
116.26 +import java.math.BigDecimal;
116.27 +import java.math.MathContext;
116.28 +import java.math.RoundingMode;
116.29 +import java.util.List;
116.30 +import java.util.logging.Level;
116.31 +import java.util.logging.Logger;
116.32 +
116.33 +/**
116.34 + * TODO: min/max values – range for case that no value is 100 %
116.35 + *
116.36 + * TODO: multiple barcharts in same table (last column is still default) + multiple resultsets
116.37 + *
116.38 + * TODO: negative values - bar starting from the middle, not always from the left
116.39 + *
116.40 + * @author Ing. František Kučera (frantovo.cz)
116.41 + */
116.42 +@PropertyDeclaration(name = BarChartFormatter.PROPERTY_PRECISION, type = Integer.class, defaultValue = BarChartFormatter.PROPERTY_PRECISION_DEFAULT, description = "number of characters representing 100 % in the bar chart")
116.43 +public class BarChartFormatter extends TabularPrefetchingFormatter {
116.44 +
116.45 + public static final String NAME = "barchart"; // bash-completion:formatter
116.46 + public static final String PROPERTY_PRECISION = "precision";
116.47 + protected static final String PROPERTY_PRECISION_DEFAULT = "100";
116.48 + private static final MathContext mathContext = MathContext.DECIMAL128;
116.49 + public static final Logger log = LoggerProducer.getLogger();
116.50 + private final BigDecimal chartPrecision;
116.51 + private final char chartFull;
116.52 + private final char chartEmpty;
116.53 +
116.54 + public BarChartFormatter(FormatterContext formatterContext) {
116.55 + super(formatterContext);
116.56 + chartPrecision = BigDecimal.valueOf(formatterContext.getProperties().getInteger(PROPERTY_PRECISION, Integer.parseInt(PROPERTY_PRECISION_DEFAULT)));
116.57 + chartFull = isAsciiNostalgia() ? '#' : '█';
116.58 + chartEmpty = isAsciiNostalgia() ? '~' : '░';
116.59 + // TODO: consider using partial blocks for more precision: https://en.wikipedia.org/wiki/Block_Elements
116.60 + }
116.61 +
116.62 + @Override
116.63 + protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
116.64 + super.postprocessPrefetchedResultSet(currentHeader, currentResultSet);
116.65 +
116.66 + updateColumnWidth(currentHeader.getColumnCount(), chartPrecision.intValue());
116.67 +
116.68 + BigDecimal maximum = BigDecimal.ZERO;
116.69 + BigDecimal minimum = BigDecimal.ZERO;
116.70 + int lastIndex = currentHeader.getColumnCount() - 1;
116.71 +
116.72 + Object valueObject = null;
116.73 + try {
116.74 + for (Object[] row : currentResultSet) {
116.75 + valueObject = row[lastIndex];
116.76 + if (valueObject != null) {
116.77 + BigDecimal value = new BigDecimal(valueObject.toString());
116.78 + maximum = maximum.max(value);
116.79 + minimum = minimum.min(value);
116.80 + }
116.81 + }
116.82 +
116.83 + BigDecimal range = maximum.subtract(minimum);
116.84 +
116.85 + for (Object[] row : currentResultSet) {
116.86 + valueObject = row[lastIndex];
116.87 + if (valueObject == null) {
116.88 + row[lastIndex] = "";
116.89 + } else {
116.90 + BigDecimal value = new BigDecimal(valueObject.toString());
116.91 + BigDecimal valueFromMinimum = value.subtract(minimum);
116.92 +
116.93 + BigDecimal points = chartPrecision.divide(range, mathContext).multiply(valueFromMinimum, mathContext);
116.94 + int pointsRounded = points.setScale(0, RoundingMode.HALF_UP).intValue();
116.95 + row[lastIndex] = Functions.repeat(chartFull, pointsRounded) + Functions.repeat(chartEmpty, chartPrecision.intValue() - pointsRounded);
116.96 + }
116.97 + }
116.98 +
116.99 + } catch (NumberFormatException e) {
116.100 + // https://en.wiktionary.org/wiki/parsable
116.101 + log.log(Level.SEVERE, "Last column must be number or an object with toString() value parsable to a number. But was „{0}“", valueObject);
116.102 + // FIXME: throw FormatterException
116.103 + throw e;
116.104 + }
116.105 + }
116.106 +
116.107 +}
117.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
117.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnDescriptor.java Mon Mar 04 20:15:24 2019 +0100
117.3 @@ -0,0 +1,122 @@
117.4 +/**
117.5 + * SQL-DK
117.6 + * Copyright © 2013 František Kučera (frantovo.cz)
117.7 + *
117.8 + * This program is free software: you can redistribute it and/or modify
117.9 + * it under the terms of the GNU General Public License as published by
117.10 + * the Free Software Foundation, either version 3 of the License, or
117.11 + * (at your option) any later version.
117.12 + *
117.13 + * This program is distributed in the hope that it will be useful,
117.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
117.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117.16 + * GNU General Public License for more details.
117.17 + *
117.18 + * You should have received a copy of the GNU General Public License
117.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
117.20 + */
117.21 +package info.globalcode.sql.dk.formatting;
117.22 +
117.23 +import java.sql.Types;
117.24 +
117.25 +/**
117.26 + *
117.27 + * @author Ing. František Kučera (frantovo.cz)
117.28 + */
117.29 +public class ColumnDescriptor {
117.30 +
117.31 + private String name;
117.32 + private String label;
117.33 + private int type;
117.34 + private String typeName;
117.35 + private boolean firstColumn;
117.36 + private boolean lastColumn;
117.37 + private int columnNumber;
117.38 +
117.39 + /**
117.40 + * @return column name
117.41 + * @see #getLabel()
117.42 + */
117.43 + public String getName() {
117.44 + return name;
117.45 + }
117.46 +
117.47 + public void setName(String name) {
117.48 + this.name = name;
117.49 + }
117.50 +
117.51 + /**
117.52 + * @return label specified by the SQL AS clause
117.53 + */
117.54 + public String getLabel() {
117.55 + return label;
117.56 + }
117.57 +
117.58 + public void setLabel(String label) {
117.59 + this.label = label;
117.60 + }
117.61 +
117.62 + public int getType() {
117.63 + return type;
117.64 + }
117.65 +
117.66 + public void setType(int type) {
117.67 + this.type = type;
117.68 + }
117.69 +
117.70 + public String getTypeName() {
117.71 + return typeName;
117.72 + }
117.73 +
117.74 + public void setTypeName(String typeName) {
117.75 + this.typeName = typeName;
117.76 + }
117.77 +
117.78 + public boolean isFirstColumn() {
117.79 + return firstColumn;
117.80 + }
117.81 +
117.82 + public void setFirstColumn(boolean firstColumn) {
117.83 + this.firstColumn = firstColumn;
117.84 + }
117.85 +
117.86 + public boolean isLastColumn() {
117.87 + return lastColumn;
117.88 + }
117.89 +
117.90 + public void setLastColumn(boolean lastColumn) {
117.91 + this.lastColumn = lastColumn;
117.92 + }
117.93 +
117.94 + /**
117.95 + * @return number of this column, 1 = first
117.96 + */
117.97 + public int getColumnNumber() {
117.98 + return columnNumber;
117.99 + }
117.100 +
117.101 + public void setColumnNumber(int columnNumber) {
117.102 + this.columnNumber = columnNumber;
117.103 + }
117.104 +
117.105 + public boolean isBoolean() {
117.106 + return type == Types.BOOLEAN;
117.107 + }
117.108 +
117.109 + public boolean isNumeric() {
117.110 + switch (type) {
117.111 + case Types.BIGINT:
117.112 + case Types.DECIMAL:
117.113 + case Types.DOUBLE:
117.114 + case Types.FLOAT:
117.115 + case Types.INTEGER:
117.116 + case Types.NUMERIC:
117.117 + case Types.REAL:
117.118 + case Types.SMALLINT:
117.119 + case Types.TINYINT:
117.120 + return true;
117.121 + default:
117.122 + return false;
117.123 + }
117.124 + }
117.125 +}
118.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
118.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/ColumnsHeader.java Mon Mar 04 20:15:24 2019 +0100
118.3 @@ -0,0 +1,70 @@
118.4 +/**
118.5 + * SQL-DK
118.6 + * Copyright © 2013 František Kučera (frantovo.cz)
118.7 + *
118.8 + * This program is free software: you can redistribute it and/or modify
118.9 + * it under the terms of the GNU General Public License as published by
118.10 + * the Free Software Foundation, either version 3 of the License, or
118.11 + * (at your option) any later version.
118.12 + *
118.13 + * This program is distributed in the hope that it will be useful,
118.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
118.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
118.16 + * GNU General Public License for more details.
118.17 + *
118.18 + * You should have received a copy of the GNU General Public License
118.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
118.20 + */
118.21 +package info.globalcode.sql.dk.formatting;
118.22 +
118.23 +import java.sql.ResultSetMetaData;
118.24 +import java.sql.SQLException;
118.25 +import java.util.ArrayList;
118.26 +import java.util.List;
118.27 +
118.28 +/**
118.29 + *
118.30 + * @author Ing. František Kučera (frantovo.cz)
118.31 + */
118.32 +public class ColumnsHeader {
118.33 +
118.34 + private ResultSetMetaData metaData;
118.35 +
118.36 + public ColumnsHeader(ResultSetMetaData metaData) {
118.37 + this.metaData = metaData;
118.38 + }
118.39 +
118.40 + public int getColumnCount() {
118.41 + try {
118.42 + return metaData.getColumnCount();
118.43 + } catch (SQLException e) {
118.44 + throw new IllegalStateException("Error during getting column count.", e);
118.45 + }
118.46 + }
118.47 +
118.48 + public List<ColumnDescriptor> getColumnDescriptors() {
118.49 + try {
118.50 + int count = metaData.getColumnCount();
118.51 + List<ColumnDescriptor> list = new ArrayList<>(count);
118.52 +
118.53 + for (int i = 1; i <= count; i++) {
118.54 + ColumnDescriptor cd = new ColumnDescriptor();
118.55 +
118.56 + cd.setFirstColumn(i == 1);
118.57 + cd.setLastColumn(i == count);
118.58 + cd.setColumnNumber(i);
118.59 +
118.60 + cd.setLabel(metaData.getColumnLabel(i));
118.61 + cd.setName(metaData.getColumnName(i));
118.62 + cd.setType(metaData.getColumnType(i));
118.63 + cd.setTypeName(metaData.getColumnTypeName(i));
118.64 + /** TODO: more properties */
118.65 + list.add(cd);
118.66 + }
118.67 +
118.68 + return list;
118.69 + } catch (SQLException e) {
118.70 + throw new IllegalStateException("Error during building column descriptors.", e);
118.71 + }
118.72 + }
118.73 +}
119.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
119.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/CommonProperties.java Mon Mar 04 20:15:24 2019 +0100
119.3 @@ -0,0 +1,50 @@
119.4 +/**
119.5 + * SQL-DK
119.6 + * Copyright © 2015 František Kučera (frantovo.cz)
119.7 + *
119.8 + * This program is free software: you can redistribute it and/or modify
119.9 + * it under the terms of the GNU General Public License as published by
119.10 + * the Free Software Foundation, either version 3 of the License, or
119.11 + * (at your option) any later version.
119.12 + *
119.13 + * This program is distributed in the hope that it will be useful,
119.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
119.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
119.16 + * GNU General Public License for more details.
119.17 + *
119.18 + * You should have received a copy of the GNU General Public License
119.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
119.20 + */
119.21 +package info.globalcode.sql.dk.formatting;
119.22 +
119.23 +import java.util.Collections;
119.24 +import java.util.HashMap;
119.25 +import java.util.Map;
119.26 +
119.27 +/**
119.28 + *
119.29 + * @author Ing. František Kučera (frantovo.cz)
119.30 + */
119.31 +public class CommonProperties {
119.32 +
119.33 + private static final Map<Class, String> TYPE_SIMPLE_NAMES;
119.34 +
119.35 + static {
119.36 + Map<Class, String> m = new HashMap<>();
119.37 + m.put(Boolean.class, "boolean");
119.38 + m.put(String.class, "String");
119.39 + m.put(Character.class, "char");
119.40 + m.put(Integer.class, "int");
119.41 + m.put(Long.class, "long");
119.42 + m.put(Double.class, "double");
119.43 + TYPE_SIMPLE_NAMES = Collections.unmodifiableMap(m);
119.44 + }
119.45 +
119.46 + public static String getSimpleTypeName(Class type) {
119.47 + String name = TYPE_SIMPLE_NAMES.get(type);
119.48 + return name == null ? type.getName() : name;
119.49 + }
119.50 +
119.51 + public static final String COLORFUL = "color";
119.52 + public static final String COLORFUL_DESCRIPTION = "whether the output should be printed in color (ANSI Escape Sequences)";
119.53 +}
120.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
120.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/FakeSqlArray.java Mon Mar 04 20:15:24 2019 +0100
120.3 @@ -0,0 +1,106 @@
120.4 +/**
120.5 + * SQL-DK
120.6 + * Copyright © 2014 František Kučera (frantovo.cz)
120.7 + *
120.8 + * This program is free software: you can redistribute it and/or modify
120.9 + * it under the terms of the GNU General Public License as published by
120.10 + * the Free Software Foundation, either version 3 of the License, or
120.11 + * (at your option) any later version.
120.12 + *
120.13 + * This program is distributed in the hope that it will be useful,
120.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
120.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
120.16 + * GNU General Public License for more details.
120.17 + *
120.18 + * You should have received a copy of the GNU General Public License
120.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
120.20 + */
120.21 +package info.globalcode.sql.dk.formatting;
120.22 +
120.23 +import info.globalcode.sql.dk.SQLType;
120.24 +import java.sql.Array;
120.25 +import java.sql.ResultSet;
120.26 +import java.sql.SQLException;
120.27 +import java.util.Map;
120.28 +
120.29 +/**
120.30 + * Fake SQL array, for formatting purposes only
120.31 + *
120.32 + * @author Ing. František Kučera (frantovo.cz)
120.33 + */
120.34 +public class FakeSqlArray implements Array {
120.35 +
120.36 + private static final UnsupportedOperationException exception = new UnsupportedOperationException("This is just a fake SQL array.");
120.37 + private final Object[] data;
120.38 + private final SQLType baseType;
120.39 +
120.40 + public FakeSqlArray(Object[] data, SQLType baseType) {
120.41 + this.data = data;
120.42 + this.baseType = baseType;
120.43 + }
120.44 +
120.45 + @Override
120.46 + public String toString() {
120.47 + StringBuilder string = new StringBuilder();
120.48 + for (Object o : data) {
120.49 + string.append(o);
120.50 + string.append("\n");
120.51 + }
120.52 + return string.toString();
120.53 + }
120.54 +
120.55 + @Override
120.56 + public String getBaseTypeName() throws SQLException {
120.57 + return baseType.name();
120.58 + }
120.59 +
120.60 + @Override
120.61 + public int getBaseType() throws SQLException {
120.62 + return baseType.getCode();
120.63 + }
120.64 +
120.65 + @Override
120.66 + public Object getArray() throws SQLException {
120.67 + return data;
120.68 + }
120.69 +
120.70 + @Override
120.71 + public Object getArray(Map<String, Class<?>> map) throws SQLException {
120.72 + throw exception;
120.73 + }
120.74 +
120.75 + @Override
120.76 + public Object getArray(long index, int count) throws SQLException {
120.77 + throw exception;
120.78 + }
120.79 +
120.80 + @Override
120.81 + public Object getArray(long index, int count, Map<String, Class<?>> map) throws SQLException {
120.82 + throw exception;
120.83 + }
120.84 +
120.85 + @Override
120.86 + public ResultSet getResultSet() throws SQLException {
120.87 + throw exception;
120.88 + }
120.89 +
120.90 + @Override
120.91 + public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException {
120.92 + throw exception;
120.93 + }
120.94 +
120.95 + @Override
120.96 + public ResultSet getResultSet(long index, int count) throws SQLException {
120.97 + throw exception;
120.98 + }
120.99 +
120.100 + @Override
120.101 + public ResultSet getResultSet(long index, int count, Map<String, Class<?>> map) throws SQLException {
120.102 + throw exception;
120.103 + }
120.104 +
120.105 + @Override
120.106 + public void free() throws SQLException {
120.107 + throw exception;
120.108 + }
120.109 +}
121.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/Formatter.java Mon Mar 04 20:15:24 2019 +0100
121.3 @@ -0,0 +1,67 @@
121.4 +/**
121.5 + * SQL-DK
121.6 + * Copyright © 2013 František Kučera (frantovo.cz)
121.7 + *
121.8 + * This program is free software: you can redistribute it and/or modify
121.9 + * it under the terms of the GNU General Public License as published by
121.10 + * the Free Software Foundation, either version 3 of the License, or
121.11 + * (at your option) any later version.
121.12 + *
121.13 + * This program is distributed in the hope that it will be useful,
121.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
121.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
121.16 + * GNU General Public License for more details.
121.17 + *
121.18 + * You should have received a copy of the GNU General Public License
121.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
121.20 + */
121.21 +package info.globalcode.sql.dk.formatting;
121.22 +
121.23 +import info.globalcode.sql.dk.Parameter;
121.24 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
121.25 +import java.util.List;
121.26 +
121.27 +/**
121.28 + * The formatter is responsible for printing the result sets and/or updates result (count of
121.29 + * inserted/updated rows). The formatter can produce output in arbitrary format – text, some markup
121.30 + * or even binary data.
121.31 + *
121.32 + * @author Ing. František Kučera (frantovo.cz)
121.33 + */
121.34 +public interface Formatter extends AutoCloseable {
121.35 +
121.36 + void writeStartBatch();
121.37 +
121.38 + void writeStartDatabase(DatabaseDefinition databaseDefinition);
121.39 +
121.40 + void writeEndDatabase();
121.41 +
121.42 + void writeStartStatement();
121.43 +
121.44 + void writeEndStatement();
121.45 +
121.46 + void writeQuery(String sql);
121.47 +
121.48 + void writeParameters(List<? extends Parameter> parameters);
121.49 +
121.50 + void writeStartResultSet(ColumnsHeader header);
121.51 +
121.52 + void writeEndResultSet();
121.53 +
121.54 + void writeStartRow();
121.55 +
121.56 + void writeColumnValue(Object value);
121.57 +
121.58 + void writeEndRow();
121.59 +
121.60 + void writeUpdatesResult(int updatedRowsCount);
121.61 +
121.62 + void writeEndBatch();
121.63 +
121.64 + /**
121.65 + * If an error occurs (e.g. lost connection during result set reading) this method will be
121.66 + * called even if there was no {@linkplain #writeEndBach()}.
121.67 + */
121.68 + @Override
121.69 + void close() throws FormatterException;
121.70 +}
122.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
122.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/FormatterContext.java Mon Mar 04 20:15:24 2019 +0100
122.3 @@ -0,0 +1,49 @@
122.4 +/**
122.5 + * SQL-DK
122.6 + * Copyright © 2013 František Kučera (frantovo.cz)
122.7 + *
122.8 + * This program is free software: you can redistribute it and/or modify
122.9 + * it under the terms of the GNU General Public License as published by
122.10 + * the Free Software Foundation, either version 3 of the License, or
122.11 + * (at your option) any later version.
122.12 + *
122.13 + * This program is distributed in the hope that it will be useful,
122.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
122.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
122.16 + * GNU General Public License for more details.
122.17 + *
122.18 + * You should have received a copy of the GNU General Public License
122.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
122.20 + */
122.21 +package info.globalcode.sql.dk.formatting;
122.22 +
122.23 +import info.globalcode.sql.dk.configuration.Properties;
122.24 +import java.io.OutputStream;
122.25 +
122.26 +/**
122.27 + * To be passed from the SQL-DK core to the formatter.
122.28 + *
122.29 + * @author Ing. František Kučera (frantovo.cz)
122.30 + */
122.31 +public class FormatterContext {
122.32 +
122.33 + private OutputStream outputStream;
122.34 + private Properties properties;
122.35 +
122.36 + public FormatterContext(OutputStream outputStream, Properties properties) {
122.37 + this.outputStream = outputStream;
122.38 + this.properties = properties;
122.39 + }
122.40 +
122.41 + public OutputStream getOutputStream() {
122.42 + return outputStream;
122.43 + }
122.44 +
122.45 + public Properties getProperties() {
122.46 + return properties;
122.47 + }
122.48 +
122.49 + public void setProperties(Properties properties) {
122.50 + this.properties = properties;
122.51 + }
122.52 +}
123.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
123.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/FormatterException.java Mon Mar 04 20:15:24 2019 +0100
123.3 @@ -0,0 +1,42 @@
123.4 +/**
123.5 + * SQL-DK
123.6 + * Copyright © 2013 František Kučera (frantovo.cz)
123.7 + *
123.8 + * This program is free software: you can redistribute it and/or modify
123.9 + * it under the terms of the GNU General Public License as published by
123.10 + * the Free Software Foundation, either version 3 of the License, or
123.11 + * (at your option) any later version.
123.12 + *
123.13 + * This program is distributed in the hope that it will be useful,
123.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
123.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
123.16 + * GNU General Public License for more details.
123.17 + *
123.18 + * You should have received a copy of the GNU General Public License
123.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
123.20 + */
123.21 +package info.globalcode.sql.dk.formatting;
123.22 +
123.23 +import info.globalcode.sql.dk.DKException;
123.24 +
123.25 +/**
123.26 + *
123.27 + * @author Ing. František Kučera (frantovo.cz)
123.28 + */
123.29 +public class FormatterException extends DKException {
123.30 +
123.31 + public FormatterException() {
123.32 + }
123.33 +
123.34 + public FormatterException(String message) {
123.35 + super(message);
123.36 + }
123.37 +
123.38 + public FormatterException(Throwable cause) {
123.39 + super(cause);
123.40 + }
123.41 +
123.42 + public FormatterException(String message, Throwable cause) {
123.43 + super(message, cause);
123.44 + }
123.45 +}
124.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/SilentFormatter.java Mon Mar 04 20:15:24 2019 +0100
124.3 @@ -0,0 +1,33 @@
124.4 +/**
124.5 + * SQL-DK
124.6 + * Copyright © 2013 František Kučera (frantovo.cz)
124.7 + *
124.8 + * This program is free software: you can redistribute it and/or modify
124.9 + * it under the terms of the GNU General Public License as published by
124.10 + * the Free Software Foundation, either version 3 of the License, or
124.11 + * (at your option) any later version.
124.12 + *
124.13 + * This program is distributed in the hope that it will be useful,
124.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
124.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
124.16 + * GNU General Public License for more details.
124.17 + *
124.18 + * You should have received a copy of the GNU General Public License
124.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
124.20 + */
124.21 +package info.globalcode.sql.dk.formatting;
124.22 +
124.23 +/**
124.24 + * Does not output anything, can be used instead of
124.25 + * <code>/dev/null</code>.
124.26 + *
124.27 + * @author Ing. František Kučera (frantovo.cz)
124.28 + */
124.29 +public class SilentFormatter extends AbstractFormatter {
124.30 +
124.31 + public static final String NAME = "silent"; // bash-completion:formatter
124.32 +
124.33 + public SilentFormatter(FormatterContext formatterContext) {
124.34 + super(formatterContext);
124.35 + }
124.36 +}
125.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/SingleRecordFormatter.java Mon Mar 04 20:15:24 2019 +0100
125.3 @@ -0,0 +1,105 @@
125.4 +/**
125.5 + * SQL-DK
125.6 + * Copyright © 2015 František Kučera (frantovo.cz)
125.7 + *
125.8 + * This program is free software: you can redistribute it and/or modify
125.9 + * it under the terms of the GNU General Public License as published by
125.10 + * the Free Software Foundation, either version 3 of the License, or
125.11 + * (at your option) any later version.
125.12 + *
125.13 + * This program is distributed in the hope that it will be useful,
125.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
125.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
125.16 + * GNU General Public License for more details.
125.17 + *
125.18 + * You should have received a copy of the GNU General Public License
125.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
125.20 + */
125.21 +package info.globalcode.sql.dk.formatting;
125.22 +
125.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
125.24 +import info.globalcode.sql.dk.Functions;
125.25 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
125.26 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
125.27 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
125.28 +
125.29 +/**
125.30 + * Formatter intended for printing one record (or few records) with many columns.
125.31 + * Prints each colum name and its value on separate line.
125.32 + *
125.33 + * @author Ing. František Kučera (frantovo.cz)
125.34 + */
125.35 +@PropertyDeclaration(name = COLORFUL, defaultValue = "true", type = Boolean.class, description = COLORFUL_DESCRIPTION)
125.36 +public class SingleRecordFormatter extends AbstractFormatter {
125.37 +
125.38 + public static final String NAME = "record"; // bash-completion:formatter
125.39 + private final ColorfulPrintWriter out;
125.40 + private boolean firstResult = true;
125.41 +
125.42 + public SingleRecordFormatter(FormatterContext formatterContext) {
125.43 + super(formatterContext);
125.44 + out = new ColorfulPrintWriter(formatterContext.getOutputStream());
125.45 + out.setColorful(formatterContext.getProperties().getBoolean(COLORFUL, true));
125.46 + }
125.47 +
125.48 + @Override
125.49 + public void writeStartResultSet(ColumnsHeader header) {
125.50 + super.writeStartResultSet(header);
125.51 + printResultSeparator();
125.52 + }
125.53 +
125.54 + @Override
125.55 + public void writeStartRow() {
125.56 + super.writeStartRow();
125.57 + printRecordSeparator();
125.58 + out.print(ColorfulPrintWriter.TerminalColor.Red, "Record: ");
125.59 + out.print(getCurrentRowCount());
125.60 + println();
125.61 + }
125.62 +
125.63 + @Override
125.64 + public void writeColumnValue(Object value) {
125.65 + super.writeColumnValue(value);
125.66 + String columnName = getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel();
125.67 + out.print(ColorfulPrintWriter.TerminalColor.Green, columnName + ": ");
125.68 + Functions.printValueWithWhitespaceReplaced(out, toString(value), null, ColorfulPrintWriter.TerminalColor.Red);
125.69 + println();
125.70 + }
125.71 +
125.72 + private static String toString(Object value) {
125.73 + return String.valueOf(value);
125.74 + }
125.75 +
125.76 + @Override
125.77 + public void writeUpdatesResult(int updatedRowsCount) {
125.78 + super.writeUpdatesResult(updatedRowsCount);
125.79 + printResultSeparator();
125.80 + out.print(ColorfulPrintWriter.TerminalColor.Red, "Updated records: ");
125.81 + out.println(updatedRowsCount);
125.82 + printBellAndFlush();
125.83 + }
125.84 +
125.85 + private void printBellAndFlush() {
125.86 + out.bell();
125.87 + out.flush();
125.88 + }
125.89 +
125.90 + private void println() {
125.91 + out.println();
125.92 + printBellAndFlush();
125.93 + }
125.94 +
125.95 + private void printRecordSeparator() {
125.96 + if (getCurrentRowCount() > 1) {
125.97 + println();
125.98 + }
125.99 + }
125.100 +
125.101 + private void printResultSeparator() {
125.102 + if (firstResult) {
125.103 + firstResult = false;
125.104 + } else {
125.105 + println();
125.106 + }
125.107 + }
125.108 +}
126.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/SingleValueFormatter.java Mon Mar 04 20:15:24 2019 +0100
126.3 @@ -0,0 +1,52 @@
126.4 +/**
126.5 + * SQL-DK
126.6 + * Copyright © 2013 František Kučera (frantovo.cz)
126.7 + *
126.8 + * This program is free software: you can redistribute it and/or modify
126.9 + * it under the terms of the GNU General Public License as published by
126.10 + * the Free Software Foundation, either version 3 of the License, or
126.11 + * (at your option) any later version.
126.12 + *
126.13 + * This program is distributed in the hope that it will be useful,
126.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
126.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
126.16 + * GNU General Public License for more details.
126.17 + *
126.18 + * You should have received a copy of the GNU General Public License
126.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
126.20 + */
126.21 +package info.globalcode.sql.dk.formatting;
126.22 +
126.23 +import java.io.PrintWriter;
126.24 +
126.25 +/**
126.26 + * Prints just the value without any formatting. If the result set contains multiple records or
126.27 + * columns, the values are simply concatenate without any separators. If updates result is returned,
126.28 + * the updated records count is printed.
126.29 + *
126.30 + * @author Ing. František Kučera (frantovo.cz)
126.31 + */
126.32 +public class SingleValueFormatter extends AbstractFormatter {
126.33 +
126.34 + public static final String NAME = "single"; // bash-completion:formatter
126.35 + private PrintWriter out;
126.36 +
126.37 + public SingleValueFormatter(FormatterContext formatterContext) {
126.38 + super(formatterContext);
126.39 + this.out = new PrintWriter(formatterContext.getOutputStream());
126.40 + }
126.41 +
126.42 + @Override
126.43 + public void writeColumnValue(Object value) {
126.44 + super.writeColumnValue(value);
126.45 + out.print(String.valueOf(value));
126.46 + out.flush();
126.47 + }
126.48 +
126.49 + @Override
126.50 + public void writeUpdatesResult(int updatedRowsCount) {
126.51 + super.writeUpdatesResult(updatedRowsCount);
126.52 + out.print(updatedRowsCount);
126.53 + out.flush();
126.54 + }
126.55 +}
127.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/TabularFormatter.java Mon Mar 04 20:15:24 2019 +0100
127.3 @@ -0,0 +1,308 @@
127.4 +/**
127.5 + * SQL-DK
127.6 + * Copyright © 2013 František Kučera (frantovo.cz)
127.7 + *
127.8 + * This program is free software: you can redistribute it and/or modify
127.9 + * it under the terms of the GNU General Public License as published by
127.10 + * the Free Software Foundation, either version 3 of the License, or
127.11 + * (at your option) any later version.
127.12 + *
127.13 + * This program is distributed in the hope that it will be useful,
127.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
127.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
127.16 + * GNU General Public License for more details.
127.17 + *
127.18 + * You should have received a copy of the GNU General Public License
127.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
127.20 + */
127.21 +package info.globalcode.sql.dk.formatting;
127.22 +
127.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
127.24 +import static info.globalcode.sql.dk.ColorfulPrintWriter.*;
127.25 +import info.globalcode.sql.dk.Functions;
127.26 +import static info.globalcode.sql.dk.Functions.lpad;
127.27 +import static info.globalcode.sql.dk.Functions.rpad;
127.28 +import static info.globalcode.sql.dk.Functions.repeat;
127.29 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
127.30 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
127.31 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
127.32 +import java.sql.SQLException;
127.33 +import java.sql.SQLXML;
127.34 +import java.util.List;
127.35 +import java.util.logging.Level;
127.36 +import java.util.logging.Logger;
127.37 +
127.38 +/**
127.39 + * <p>
127.40 + * Prints human-readable output – tables of result sets and text messages with update counts.
127.41 + * </p>
127.42 + *
127.43 + * <p>
127.44 + * Longer values might break the table – overflow the cells – see alternative tabular formatters and
127.45 + * the {@linkplain #PROPERTY_TRIM} property.
127.46 + * </p>
127.47 + *
127.48 + * @author Ing. František Kučera (frantovo.cz)
127.49 + * @see TabularPrefetchingFormatter
127.50 + * @see TabularWrappingFormatter
127.51 + */
127.52 +@PropertyDeclaration(name = COLORFUL, defaultValue = "true", type = Boolean.class, description = COLORFUL_DESCRIPTION)
127.53 +@PropertyDeclaration(name = TabularFormatter.PROPERTY_ASCII, defaultValue = "false", type = Boolean.class, description = "whether to use ASCII table borders instead of unicode ones")
127.54 +@PropertyDeclaration(name = TabularFormatter.PROPERTY_TRIM, defaultValue = "false", type = Boolean.class, description = "whether to trim the values to fit the column width")
127.55 +@PropertyDeclaration(name = TabularFormatter.PROPERTY_HEADER_TYPE, defaultValue = "true", type = Boolean.class, description = "whether to print data types in column headers")
127.56 +public class TabularFormatter extends AbstractFormatter {
127.57 +
127.58 + private static final Logger log = Logger.getLogger(TabularFormatter.class.getName());
127.59 + public static final String NAME = "tabular"; // bash-completion:formatter
127.60 + private static final String HEADER_TYPE_PREFIX = " (";
127.61 + private static final String HEADER_TYPE_SUFFIX = ")";
127.62 + public static final String PROPERTY_ASCII = "ascii";
127.63 + public static final String PROPERTY_TRIM = "trim";
127.64 + public static final String PROPERTY_HEADER_TYPE = "headerTypes";
127.65 + protected ColorfulPrintWriter out;
127.66 + private boolean firstResult = true;
127.67 + private int[] columnWidth;
127.68 + /**
127.69 + * use ASCII borders instead of unicode ones
127.70 + */
127.71 + private final boolean asciiNostalgia;
127.72 + /**
127.73 + * Trim values if they are longer than cell size
127.74 + */
127.75 + private final boolean trimValues;
127.76 + /**
127.77 + * Print data type of each column in the header
127.78 + */
127.79 + private final boolean printHeaderTypes;
127.80 +
127.81 + public TabularFormatter(FormatterContext formatterContext) {
127.82 + super(formatterContext);
127.83 + out = new ColorfulPrintWriter(formatterContext.getOutputStream());
127.84 + asciiNostalgia = formatterContext.getProperties().getBoolean(PROPERTY_ASCII, false);
127.85 + trimValues = formatterContext.getProperties().getBoolean(PROPERTY_TRIM, false);
127.86 + printHeaderTypes = formatterContext.getProperties().getBoolean(PROPERTY_HEADER_TYPE, true);
127.87 + out.setColorful(formatterContext.getProperties().getBoolean(COLORFUL, true));
127.88 + }
127.89 +
127.90 + @Override
127.91 + public void writeStartResultSet(ColumnsHeader header) {
127.92 + super.writeStartResultSet(header);
127.93 + printResultSeparator();
127.94 +
127.95 + initColumnWidths(header.getColumnCount());
127.96 +
127.97 + printTableIndent();
127.98 + printTableBorder("╭");
127.99 +
127.100 + List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
127.101 +
127.102 + for (ColumnDescriptor cd : columnDescriptors) {
127.103 + // padding: make header cell at least same width as data cells in this column
127.104 + int typeWidth = printHeaderTypes ? cd.getTypeName().length() + HEADER_TYPE_PREFIX.length() + HEADER_TYPE_SUFFIX.length() : 0;
127.105 + cd.setLabel(rpad(cd.getLabel(), getColumnWidth(cd.getColumnNumber()) - typeWidth));
127.106 + updateColumnWidth(cd.getColumnNumber(), cd.getLabel().length() + typeWidth);
127.107 +
127.108 + if (!cd.isFirstColumn()) {
127.109 + printTableBorder("┬");
127.110 + }
127.111 + printTableBorder(repeat('─', getColumnWidth(cd.getColumnNumber()) + 2));
127.112 + }
127.113 + printTableBorder("╮");
127.114 + out.println();
127.115 +
127.116 + for (ColumnDescriptor cd : columnDescriptors) {
127.117 + if (cd.isFirstColumn()) {
127.118 + printTableIndent();
127.119 + printTableBorder("│ ");
127.120 + } else {
127.121 + printTableBorder(" │ ");
127.122 + }
127.123 + out.print(TerminalStyle.Bright, cd.getLabel());
127.124 + if (printHeaderTypes) {
127.125 + out.print(HEADER_TYPE_PREFIX);
127.126 + out.print(cd.getTypeName());
127.127 + out.print(HEADER_TYPE_SUFFIX);
127.128 + }
127.129 + if (cd.isLastColumn()) {
127.130 + printTableBorder(" │");
127.131 + }
127.132 + }
127.133 + out.println();
127.134 +
127.135 + printTableIndent();
127.136 + printTableBorder("├");
127.137 + for (int i = 1; i <= header.getColumnCount(); i++) {
127.138 + if (i > 1) {
127.139 + printTableBorder("┼");
127.140 + }
127.141 + printTableBorder(repeat('─', getColumnWidth(i) + 2));
127.142 + }
127.143 + printTableBorder("┤");
127.144 + out.println();
127.145 +
127.146 + out.flush();
127.147 + }
127.148 +
127.149 + /**
127.150 + * Must be called before {@linkplain #updateColumnWidth(int, int)} and
127.151 + * {@linkplain #getColumnWidth(int)} for each result set.
127.152 + *
127.153 + * @param columnCount number of columns in current result set
127.154 + */
127.155 + protected void initColumnWidths(int columnCount) {
127.156 + if (columnWidth == null) {
127.157 + columnWidth = new int[columnCount];
127.158 + }
127.159 + }
127.160 +
127.161 + protected void cleanColumnWidths() {
127.162 + columnWidth = null;
127.163 + }
127.164 +
127.165 + @Override
127.166 + public void writeColumnValue(Object value) {
127.167 + super.writeColumnValue(value);
127.168 + writeColumnValueInternal(value);
127.169 + }
127.170 +
127.171 + protected void writeColumnValueInternal(Object value) {
127.172 +
127.173 + if (isCurrentColumnFirst()) {
127.174 + printTableIndent();
127.175 + printTableBorder("│ ");
127.176 + } else {
127.177 + printTableBorder(" │ ");
127.178 + }
127.179 +
127.180 + printValueWithWhitespaceReplaced(toString(value));
127.181 +
127.182 + if (isCurrentColumnLast()) {
127.183 + printTableBorder(" │");
127.184 + }
127.185 +
127.186 + }
127.187 +
127.188 + protected void printValueWithWhitespaceReplaced(String text) {
127.189 + Functions.printValueWithWhitespaceReplaced(out, text, TerminalColor.Cyan, TerminalColor.Red);
127.190 + }
127.191 +
127.192 + protected int getColumnWidth(int columnNumber) {
127.193 + return columnWidth[columnNumber - 1];
127.194 + }
127.195 +
127.196 + private void setColumnWidth(int columnNumber, int width) {
127.197 + columnWidth[columnNumber - 1] = width;
127.198 + }
127.199 +
127.200 + protected void updateColumnWidth(int columnNumber, int width) {
127.201 + int oldWidth = getColumnWidth(columnNumber);
127.202 + setColumnWidth(columnNumber, Math.max(width, oldWidth));
127.203 +
127.204 + }
127.205 +
127.206 + protected String toString(Object value) {
127.207 + final int width = getColumnWidth(getCurrentColumnsCount());
127.208 + String result;
127.209 + if (value instanceof Number || value instanceof Boolean) {
127.210 + result = lpad(String.valueOf(value), width);
127.211 + } else {
127.212 + if (value instanceof SQLXML) {
127.213 + // TODO: move to a common method, share with other formatters
127.214 + try {
127.215 + value = ((SQLXML) value).getString();
127.216 + } catch (SQLException e) {
127.217 + log.log(Level.SEVERE, "Unable to format XML", e);
127.218 + }
127.219 + }
127.220 +
127.221 + result = rpad(String.valueOf(value), width);
127.222 + }
127.223 + // ? value = (boolean) value ? "✔" : "✗";
127.224 +
127.225 + if (trimValues && result.length() > width) {
127.226 + result = result.substring(0, width - 1) + "…";
127.227 + }
127.228 +
127.229 + return result;
127.230 + }
127.231 +
127.232 + @Override
127.233 + public void writeEndRow() {
127.234 + super.writeEndRow();
127.235 + writeEndRowInternal();
127.236 + }
127.237 +
127.238 + public void writeEndRowInternal() {
127.239 + out.println();
127.240 + out.flush();
127.241 + }
127.242 +
127.243 + @Override
127.244 + public void writeEndResultSet() {
127.245 + int columnCount = getCurrentColumnsHeader().getColumnCount();
127.246 + super.writeEndResultSet();
127.247 +
127.248 + printTableIndent();
127.249 + printTableBorder("╰");
127.250 + for (int i = 1; i <= columnCount; i++) {
127.251 + if (i > 1) {
127.252 + printTableBorder("┴");
127.253 + }
127.254 + printTableBorder(repeat('─', getColumnWidth(i) + 2));
127.255 + }
127.256 + printTableBorder("╯");
127.257 + out.println();
127.258 +
127.259 + cleanColumnWidths();
127.260 +
127.261 + out.print(TerminalColor.Yellow, "Record count: ");
127.262 + out.println(getCurrentRowCount());
127.263 + out.bell();
127.264 + out.flush();
127.265 + }
127.266 +
127.267 + @Override
127.268 + public void writeUpdatesResult(int updatedRowsCount) {
127.269 + super.writeUpdatesResult(updatedRowsCount);
127.270 + printResultSeparator();
127.271 + out.print(TerminalColor.Red, "Updated records: ");
127.272 + out.println(updatedRowsCount);
127.273 + out.bell();
127.274 + out.flush();
127.275 + }
127.276 +
127.277 + @Override
127.278 + public void writeEndDatabase() {
127.279 + super.writeEndDatabase();
127.280 + out.flush();
127.281 + }
127.282 +
127.283 + private void printResultSeparator() {
127.284 + if (firstResult) {
127.285 + firstResult = false;
127.286 + } else {
127.287 + out.println();
127.288 + }
127.289 + }
127.290 +
127.291 + protected void printTableBorder(String border) {
127.292 + if (asciiNostalgia) {
127.293 + border = border.replaceAll("─", "-");
127.294 + border = border.replaceAll("│", "|");
127.295 + border = border.replaceAll("[╭┬╮├┼┤╰┴╯]", "+");
127.296 + }
127.297 +
127.298 + out.print(TerminalColor.Green, border);
127.299 + }
127.300 +
127.301 + protected void printTableIndent() {
127.302 + out.print(" ");
127.303 + }
127.304 +
127.305 + /**
127.306 + * @return whether should print only ASCII characters instead of unlimited Unicode.
127.307 + */
127.308 + protected boolean isAsciiNostalgia() {
127.309 + return asciiNostalgia;
127.310 + }
127.311 +}
128.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/TabularPrefetchingFormatter.java Mon Mar 04 20:15:24 2019 +0100
128.3 @@ -0,0 +1,119 @@
128.4 +/**
128.5 + * SQL-DK
128.6 + * Copyright © 2013 František Kučera (frantovo.cz)
128.7 + *
128.8 + * This program is free software: you can redistribute it and/or modify
128.9 + * it under the terms of the GNU General Public License as published by
128.10 + * the Free Software Foundation, either version 3 of the License, or
128.11 + * (at your option) any later version.
128.12 + *
128.13 + * This program is distributed in the hope that it will be useful,
128.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
128.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128.16 + * GNU General Public License for more details.
128.17 + *
128.18 + * You should have received a copy of the GNU General Public License
128.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
128.20 + */
128.21 +package info.globalcode.sql.dk.formatting;
128.22 +
128.23 +import java.util.ArrayList;
128.24 +import java.util.List;
128.25 +
128.26 +/**
128.27 + * <p>
128.28 + * Prefetches whole result set and computes column widths. Whole table is flushed at once in
128.29 + * {@linkplain #writeEndResultSet()}.
128.30 + * </p>
128.31 + *
128.32 + * <p>
128.33 + * Long values will not overflow the cells, but whole result set must be loaded into the memory.
128.34 + * </p>
128.35 + *
128.36 + * @author Ing. František Kučera (frantovo.cz)
128.37 + */
128.38 +public class TabularPrefetchingFormatter extends TabularFormatter {
128.39 +
128.40 + public static final String NAME = "tabular-prefetching"; // bash-completion:formatter
128.41 + private ColumnsHeader currentHeader;
128.42 + private List<Object[]> currentResultSet;
128.43 + private Object[] currentRow;
128.44 + private int currentColumnsCount;
128.45 + private boolean prefetchDone = false;
128.46 +
128.47 + public TabularPrefetchingFormatter(FormatterContext formatterContext) {
128.48 + super(formatterContext);
128.49 + }
128.50 +
128.51 + @Override
128.52 + protected int getCurrentColumnsCount() {
128.53 + if (prefetchDone) {
128.54 + return super.getCurrentColumnsCount();
128.55 + } else {
128.56 + return currentColumnsCount;
128.57 + }
128.58 + }
128.59 +
128.60 + @Override
128.61 + public void writeStartResultSet(ColumnsHeader header) {
128.62 + currentResultSet = new ArrayList<>();
128.63 + currentHeader = header;
128.64 + initColumnWidths(header.getColumnCount());
128.65 + }
128.66 +
128.67 + @Override
128.68 + public void writeStartRow() {
128.69 + currentRow = new Object[currentHeader.getColumnCount()];
128.70 + currentResultSet.add(currentRow);
128.71 + currentColumnsCount = 0;
128.72 + }
128.73 +
128.74 + @Override
128.75 + public void writeColumnValue(Object value) {
128.76 + currentRow[currentColumnsCount] = value;
128.77 + currentColumnsCount++;
128.78 + String textRepresentation = toString(value);
128.79 + /** TODO: count only printable characters (currently not an issue) */
128.80 + updateColumnWidth(currentColumnsCount, textRepresentation.length());
128.81 + }
128.82 +
128.83 + @Override
128.84 + public void writeEndRow() {
128.85 + // do nothing
128.86 + }
128.87 +
128.88 + @Override
128.89 + public void writeEndResultSet() {
128.90 + prefetchDone = true;
128.91 +
128.92 + postprocessPrefetchedResultSet(currentHeader, currentResultSet);
128.93 +
128.94 + super.writeStartResultSet(currentHeader);
128.95 +
128.96 + for (Object[] row : currentResultSet) {
128.97 + super.writeStartRow();
128.98 + for (Object cell : row) {
128.99 + super.writeColumnValue(cell);
128.100 + }
128.101 + super.writeEndRow();
128.102 + }
128.103 +
128.104 + currentColumnsCount = 0;
128.105 + currentHeader = null;
128.106 + currentRow = null;
128.107 + currentResultSet = null;
128.108 + super.writeEndResultSet();
128.109 + prefetchDone = false;
128.110 + }
128.111 +
128.112 + /**
128.113 + * Optional post-processing – override in sub-classes if needed.
128.114 + * Don't forget to {@linkplain #updateColumnWidth(int, int)}
128.115 + *
128.116 + * @param currentHeader
128.117 + * @param currentResultSet
128.118 + */
128.119 + protected void postprocessPrefetchedResultSet(ColumnsHeader currentHeader, List<Object[]> currentResultSet) {
128.120 + }
128.121 +
128.122 +}
129.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
129.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/TabularWrappingFormatter.java Mon Mar 04 20:15:24 2019 +0100
129.3 @@ -0,0 +1,116 @@
129.4 +/**
129.5 + * SQL-DK
129.6 + * Copyright © 2014 František Kučera (frantovo.cz)
129.7 + *
129.8 + * This program is free software: you can redistribute it and/or modify
129.9 + * it under the terms of the GNU General Public License as published by
129.10 + * the Free Software Foundation, either version 3 of the License, or
129.11 + * (at your option) any later version.
129.12 + *
129.13 + * This program is distributed in the hope that it will be useful,
129.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
129.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
129.16 + * GNU General Public License for more details.
129.17 + *
129.18 + * You should have received a copy of the GNU General Public License
129.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
129.20 + */
129.21 +package info.globalcode.sql.dk.formatting;
129.22 +
129.23 +import info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
129.24 +import java.util.ArrayList;
129.25 +import java.util.List;
129.26 +import static info.globalcode.sql.dk.Functions.lpad;
129.27 +import static info.globalcode.sql.dk.Functions.rpad;
129.28 +import static info.globalcode.sql.dk.Functions.repeat;
129.29 +
129.30 +/**
129.31 + * Longer values are line-wrapped – the cell then contains multiple lines. Marks are added to
129.32 + * signalize forced line ends (not present in original data).
129.33 + *
129.34 + * @author Ing. František Kučera (frantovo.cz)
129.35 + */
129.36 +public class TabularWrappingFormatter extends TabularFormatter {
129.37 +
129.38 + public static final String NAME = "tabular-wrapping"; // bash-completion:formatter
129.39 + private List<String[]> currentRow;
129.40 +
129.41 + public TabularWrappingFormatter(FormatterContext formatterContext) {
129.42 + super(formatterContext);
129.43 + }
129.44 +
129.45 + @Override
129.46 + public void writeStartResultSet(ColumnsHeader header) {
129.47 + super.writeStartResultSet(header);
129.48 + currentRow = new ArrayList<>(header.getColumnCount());
129.49 + }
129.50 +
129.51 + @Override
129.52 + protected void writeColumnValueInternal(Object value) {
129.53 + boolean rightAlign = value instanceof Number || value instanceof Boolean;
129.54 + String valueString = String.valueOf(value);
129.55 + int columnWidth = getColumnWidth(getCurrentColumnsCount()) - 1; // -1 = space for new line symbol
129.56 + currentRow.add(wrapLines(valueString, columnWidth, rightAlign));
129.57 + }
129.58 +
129.59 + @Override
129.60 + public void writeEndRow() {
129.61 + super.writeEndRow();
129.62 +
129.63 + int wrappedLine = 0;
129.64 + boolean hasMoreWrappedLines;
129.65 +
129.66 + do {
129.67 + hasMoreWrappedLines = false;
129.68 + for (int i = 0; i < currentRow.size(); i++) {
129.69 + if (i == 0) {
129.70 + printTableIndent();
129.71 + printTableBorder("│ ");
129.72 + } else {
129.73 + printTableBorder(" │ ");
129.74 + }
129.75 + String[] columnArray = currentRow.get(i);
129.76 + if (wrappedLine < columnArray.length) {
129.77 + printValueWithWhitespaceReplaced(columnArray[wrappedLine]);
129.78 +
129.79 + if (wrappedLine < columnArray.length - 1) {
129.80 + out.print(TerminalColor.Red, "↩");
129.81 + hasMoreWrappedLines = true;
129.82 + } else {
129.83 + out.print(" ");
129.84 + }
129.85 +
129.86 + } else {
129.87 + out.print(repeat(' ', getColumnWidth(i + 1)));
129.88 + }
129.89 +
129.90 + if (i == (currentRow.size() - 1)) {
129.91 + printTableBorder(" │");
129.92 + }
129.93 + }
129.94 + out.println();
129.95 + out.flush();
129.96 + wrappedLine++;
129.97 + } while (hasMoreWrappedLines);
129.98 +
129.99 + currentRow.clear();
129.100 + }
129.101 +
129.102 + @Override
129.103 + public void writeEndRowInternal() {
129.104 + // already done – wrapped row ends
129.105 + }
129.106 +
129.107 + private static String[] wrapLines(String s, int width, boolean rightAlign) {
129.108 + String[] array = new String[(s.length() - 1) / width + 1];
129.109 + for (int i = 0; i < array.length; i++) {
129.110 + if (i == array.length - 1) {
129.111 + String part = s.substring(i * width, s.length());
129.112 + array[i] = rightAlign ? lpad(part, width) : rpad(part, width);
129.113 + } else {
129.114 + array[i] = s.substring(i * width, (i + 1) * width);
129.115 + }
129.116 + }
129.117 + return array;
129.118 + }
129.119 +}
130.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
130.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/TeXFormatter.java Mon Mar 04 20:15:24 2019 +0100
130.3 @@ -0,0 +1,208 @@
130.4 +/**
130.5 + * SQL-DK
130.6 + * Copyright © 2014 František Kučera (frantovo.cz)
130.7 + *
130.8 + * This program is free software: you can redistribute it and/or modify
130.9 + * it under the terms of the GNU General Public License as published by
130.10 + * the Free Software Foundation, either version 3 of the License, or
130.11 + * (at your option) any later version.
130.12 + *
130.13 + * This program is distributed in the hope that it will be useful,
130.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
130.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
130.16 + * GNU General Public License for more details.
130.17 + *
130.18 + * You should have received a copy of the GNU General Public License
130.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
130.20 + */
130.21 +package info.globalcode.sql.dk.formatting;
130.22 +
130.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
130.24 +import info.globalcode.sql.dk.Constants;
130.25 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
130.26 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
130.27 +import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
130.28 +import java.util.Collections;
130.29 +import java.util.HashMap;
130.30 +import java.util.List;
130.31 +import java.util.Map;
130.32 +
130.33 +/**
130.34 + * Outputs result sets in (La)TeX format.
130.35 + *
130.36 + * @author Ing. František Kučera (frantovo.cz)
130.37 + */
130.38 +@PropertyDeclaration(name = COLORFUL, defaultValue = "false", type = Boolean.class, description = COLORFUL_DESCRIPTION)
130.39 +public class TeXFormatter extends AbstractFormatter {
130.40 +
130.41 + public static final String NAME = "tex"; // bash-completion:formatter
130.42 + private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
130.43 + private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
130.44 + private static final Map<Character, String> TEX_ESCAPE_MAP;
130.45 + private final ColorfulPrintWriter out;
130.46 +
130.47 + static {
130.48 + Map<Character, String> replacements = new HashMap<>();
130.49 +
130.50 + replacements.put('\\', "\\textbackslash{}");
130.51 + replacements.put('{', "\\{{}");
130.52 + replacements.put('}', "\\}{}");
130.53 + replacements.put('_', "\\_{}");
130.54 + replacements.put('^', "\\textasciicircum{}");
130.55 + replacements.put('#', "\\#{}");
130.56 + replacements.put('&', "\\&{}");
130.57 + replacements.put('$', "\\${}");
130.58 + replacements.put('%', "\\%{}");
130.59 + replacements.put('~', "\\textasciitilde{}");
130.60 + replacements.put('-', "{-}");
130.61 +
130.62 + TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
130.63 + }
130.64 +
130.65 + public TeXFormatter(FormatterContext formatterContext) {
130.66 + super(formatterContext);
130.67 + boolean colorful = formatterContext.getProperties().getBoolean(COLORFUL, false);
130.68 + out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
130.69 + }
130.70 +
130.71 + @Override
130.72 + public void writeStartBatch() {
130.73 + super.writeStartBatch();
130.74 +
130.75 + printCommand("documentclass", "a4paper,twoside", "article", true);
130.76 + printCommand("usepackage", "T1", "fontenc", true);
130.77 + printCommand("usepackage", "utf8x", "inputenc", true);
130.78 + printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
130.79 + printBegin("document");
130.80 + }
130.81 +
130.82 + @Override
130.83 + public void writeEndBatch() {
130.84 + super.writeEndBatch();
130.85 + printEnd("document");
130.86 + }
130.87 +
130.88 + @Override
130.89 + public void writeColumnValue(Object value) {
130.90 + super.writeColumnValue(value);
130.91 + // TODO: arrays, numbers, booleans, nulls etc.:
130.92 + out.print(escapeTex(toString(value)));
130.93 +
130.94 + if (!isCurrentColumnLast()) {
130.95 + printColumnSeparator();
130.96 + }
130.97 + }
130.98 +
130.99 + @Override
130.100 + public void writeEndRow() {
130.101 + super.writeEndRow();
130.102 + printEndRow();
130.103 + }
130.104 +
130.105 + @Override
130.106 + public void writeStartResultSet(ColumnsHeader header) {
130.107 + super.writeStartResultSet(header);
130.108 + printCommand("begin", null, "tabular", false);
130.109 +
130.110 + List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
130.111 +
130.112 + StringBuilder columnAlignments = new StringBuilder();
130.113 + for (ColumnDescriptor cd : columnDescriptors) {
130.114 + if (cd.isNumeric() || cd.isBoolean()) {
130.115 + columnAlignments.append('r');
130.116 + } else {
130.117 + columnAlignments.append('l');
130.118 + }
130.119 + }
130.120 +
130.121 + printCommand(null, null, columnAlignments.toString(), true);
130.122 + printCommand("hline", null, null, true);
130.123 +
130.124 + for (ColumnDescriptor cd : columnDescriptors) {
130.125 + printCommand("textbf", null, cd.getLabel(), false);
130.126 + if (cd.isLastColumn()) {
130.127 + printEndRow();
130.128 + } else {
130.129 + printColumnSeparator();
130.130 + }
130.131 + }
130.132 +
130.133 + printCommand("hline", null, null, true);
130.134 + }
130.135 +
130.136 + @Override
130.137 + public void writeEndResultSet() {
130.138 + super.writeEndResultSet();
130.139 + printCommand("hline", null, null, true);
130.140 + printEnd("tabular");
130.141 + }
130.142 +
130.143 + private String escapeTex(String text) {
130.144 + if (text == null) {
130.145 + return null;
130.146 + } else {
130.147 + StringBuilder result = new StringBuilder(text.length() * 2);
130.148 +
130.149 + for (char ch : text.toCharArray()) {
130.150 + String replacement = TEX_ESCAPE_MAP.get(ch);
130.151 + result.append(replacement == null ? ch : replacement);
130.152 + }
130.153 +
130.154 + return result.toString();
130.155 + }
130.156 + }
130.157 +
130.158 + protected String toString(Object value) {
130.159 + return String.valueOf(value);
130.160 + }
130.161 +
130.162 + private void printColumnSeparator() {
130.163 + out.print(COMMAND_COLOR, " & ");
130.164 + }
130.165 +
130.166 + private void printEndRow() {
130.167 + out.println(COMMAND_COLOR, " \\\\");
130.168 + out.flush();
130.169 + }
130.170 +
130.171 + /**
130.172 + *
130.173 + * @param command will not be escaped – should contain just a valid TeX command name
130.174 + * @param options will not be escaped – should be properly formatted to be printed inside [
130.175 + * and ]
130.176 + * @param value will be escaped
130.177 + * @param println whether to print line end and flush
130.178 + */
130.179 + private void printCommand(String command, String options, String value, boolean println) {
130.180 +
130.181 + if (command != null) {
130.182 + out.print(COMMAND_COLOR, "\\" + command);
130.183 + }
130.184 +
130.185 + if (options != null) {
130.186 + out.print(COMMAND_COLOR, "[");
130.187 + out.print(OPTIONS_COLOR, options);
130.188 + out.print(COMMAND_COLOR, "]");
130.189 + }
130.190 +
130.191 + if (value != null) {
130.192 + out.print(COMMAND_COLOR, "{");
130.193 + out.print(escapeTex(value));
130.194 + out.print(COMMAND_COLOR, "}");
130.195 + }
130.196 +
130.197 + if (println) {
130.198 + out.println();
130.199 + out.flush();
130.200 + }
130.201 + }
130.202 +
130.203 + private void printBegin(String environment) {
130.204 + printCommand("begin", null, environment, true);
130.205 + }
130.206 +
130.207 + private void printEnd(String environment) {
130.208 + printCommand("end", null, environment, true);
130.209 + }
130.210 +
130.211 +}
131.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
131.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XhtmlFormatter.java Mon Mar 04 20:15:24 2019 +0100
131.3 @@ -0,0 +1,262 @@
131.4 +/**
131.5 + * SQL-DK
131.6 + * Copyright © 2014 František Kučera (frantovo.cz)
131.7 + *
131.8 + * This program is free software: you can redistribute it and/or modify
131.9 + * it under the terms of the GNU General Public License as published by
131.10 + * the Free Software Foundation, either version 3 of the License, or
131.11 + * (at your option) any later version.
131.12 + *
131.13 + * This program is distributed in the hope that it will be useful,
131.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
131.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
131.16 + * GNU General Public License for more details.
131.17 + *
131.18 + * You should have received a copy of the GNU General Public License
131.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
131.20 + */
131.21 +package info.globalcode.sql.dk.formatting;
131.22 +
131.23 +import info.globalcode.sql.dk.Constants;
131.24 +import info.globalcode.sql.dk.NamedParameter;
131.25 +import info.globalcode.sql.dk.Parameter;
131.26 +import info.globalcode.sql.dk.Xmlns;
131.27 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
131.28 +import info.globalcode.sql.dk.configuration.Properties;
131.29 +import info.globalcode.sql.dk.configuration.Property;
131.30 +import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
131.31 +import java.sql.Array;
131.32 +import java.sql.SQLException;
131.33 +import java.util.Date;
131.34 +import java.util.List;
131.35 +import java.util.Map;
131.36 +import java.util.Scanner;
131.37 +import java.util.logging.Level;
131.38 +import java.util.logging.Logger;
131.39 +import javax.xml.namespace.QName;
131.40 +
131.41 +/**
131.42 + * Prints result sets and parameters as tables, SQL as preformatted and updates counts as
131.43 + * paragraphs. You can pick XHTML fragments (usually tabular data) and use it on your website or use
131.44 + * whole output as preview or report.
131.45 + *
131.46 + * @author Ing. František Kučera (frantovo.cz)
131.47 + */
131.48 +public class XhtmlFormatter extends AbstractXmlFormatter {
131.49 +
131.50 + private static final Logger log = Logger.getLogger(XhtmlFormatter.class.getName());
131.51 + public static final String NAME = "xhtml"; // bash-completion:formatter
131.52 + private static final String DOCTYPE = "html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN\" \"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd\"";
131.53 + private static final String CSS_FILE = "info/globalcode/sql/dk/formatter/XhtmlFormatter.css";
131.54 + private int statementCounter = 0;
131.55 + private int resultSetCounter = 0;
131.56 + private int updatesResultCounter = 0;
131.57 +
131.58 + public XhtmlFormatter(FormatterContext formatterContext) {
131.59 + super(addDefaults(formatterContext));
131.60 + }
131.61 +
131.62 + /**
131.63 + * Do not indent text – preserve whitespace for pre elements
131.64 + */
131.65 + private static FormatterContext addDefaults(FormatterContext formatterContext) {
131.66 + Properties defaults = new Properties(1);
131.67 + defaults.add(new Property(PROPERTY_INDENT_TEXT, "false"));
131.68 + formatterContext.getProperties().setLastDefaults(defaults);
131.69 + return formatterContext;
131.70 + }
131.71 +
131.72 + @Override
131.73 + public void writeStartBatch() {
131.74 + super.writeStartBatch();
131.75 + printStartDocument();
131.76 + printDoctype(DOCTYPE);
131.77 + printStartElement(qname("html"), singleAttribute(qname("xmlns"), Xmlns.XHTML));
131.78 +
131.79 + printStartElement(qname("head"));
131.80 + printTextElement(qname("title"), null, Constants.PROGRAM_NAME + ": batch results");
131.81 + printCss();
131.82 + printEndElement();
131.83 +
131.84 + printStartElement(qname("body"));
131.85 + }
131.86 +
131.87 + private void printCss() {
131.88 +
131.89 + try (Scanner css = new Scanner(getClass().getClassLoader().getResourceAsStream(CSS_FILE))) {
131.90 + printStartElement(qname("style"), singleAttribute(qname("type"), "text/css"));
131.91 + while (css.hasNext()) {
131.92 + printText(css.nextLine(), true);
131.93 + }
131.94 + printEndElement();
131.95 + }
131.96 + }
131.97 +
131.98 + @Override
131.99 + public void writeEndBatch() {
131.100 + super.writeEndBatch();
131.101 + printEndElement();
131.102 + printEndElement();
131.103 + printEndDocument();
131.104 + }
131.105 +
131.106 + @Override
131.107 + public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
131.108 + super.writeStartDatabase(databaseDefinition);
131.109 + printTextElement(qname("h1"), null, "Database: " + databaseDefinition.getName());
131.110 +
131.111 + printStartElement(qname("p"));
131.112 + printText("This is XHTML output of batch executed at: ", true);
131.113 + printText(new Date().toString(), true);
131.114 + printEndElement();
131.115 + }
131.116 +
131.117 + @Override
131.118 + public void writeQuery(String sql) {
131.119 + super.writeQuery(sql);
131.120 + printTextElement(qname("pre"), null, sql);
131.121 + }
131.122 +
131.123 + @Override
131.124 + public void writeParameters(List<? extends Parameter> parameters) {
131.125 + super.writeParameters(parameters);
131.126 +
131.127 + if (parameters == null || parameters.isEmpty()) {
131.128 + printTextElement(qname("p"), null, "(this query has no parameters)");
131.129 + } else {
131.130 + printTextElement(qname("h3"), null, "Parameters:");
131.131 +
131.132 + printStartElement(qname("table"));
131.133 +
131.134 + printStartElement(qname("thead"));
131.135 + printStartElement(qname("tr"));
131.136 + printTextElement(qname("td"), null, "id");
131.137 + printTextElement(qname("td"), null, "type");
131.138 + printTextElement(qname("td"), null, "value");
131.139 + printEndElement();
131.140 + printEndElement();
131.141 +
131.142 + printStartElement(qname("tbody"));
131.143 + for (int i = 0; i < parameters.size(); i++) {
131.144 + Parameter p = parameters.get(i);
131.145 + printStartElement(qname("tr"));
131.146 + String numberOrName;
131.147 + if (p instanceof NamedParameter) {
131.148 + numberOrName = ((NamedParameter) p).getName();
131.149 + } else {
131.150 + numberOrName = String.valueOf(i + 1);
131.151 + }
131.152 + printTextElement(qname("td"), null, numberOrName);
131.153 + printTextElement(qname("td"), null, p.getType().name());
131.154 + printTableData(p.getValue());
131.155 + printEndElement();
131.156 + }
131.157 + printEndElement();
131.158 +
131.159 + printEndElement();
131.160 + }
131.161 + }
131.162 +
131.163 + private void printTableData(Object value) {
131.164 +
131.165 + if (value instanceof Array) {
131.166 + Array sqlArray = (Array) value;
131.167 + try {
131.168 + Object[] array = (Object[]) sqlArray.getArray();
131.169 + printStartElement(qname("td"));
131.170 + printArray(array);
131.171 + printEndElement();
131.172 + } catch (SQLException e) {
131.173 + log.log(Level.SEVERE, "Unable to format array", e);
131.174 + printTableData(String.valueOf(value));
131.175 + }
131.176 + } else {
131.177 + Map<QName, String> attributes = null;
131.178 + if (value instanceof Number) {
131.179 + attributes = singleAttribute(qname("class"), "number");
131.180 + } else if (value instanceof Boolean) {
131.181 + attributes = singleAttribute(qname("class"), "boolean");
131.182 + }
131.183 + printTextElement(qname("td"), attributes, String.valueOf(value));
131.184 + }
131.185 + }
131.186 +
131.187 + private void printArray(Object[] array) {
131.188 + printStartElement(qname("ul"));
131.189 + for (Object o : array) {
131.190 + if (o instanceof Object[]) {
131.191 + printStartElement(qname("li"));
131.192 + printTextElement(qname("p"), null, "nested array:");
131.193 + printArray((Object[]) o);
131.194 + printEndElement();
131.195 + } else {
131.196 + printTextElement(qname("li"), null, String.valueOf(o));
131.197 + }
131.198 + }
131.199 + printEndElement();
131.200 + }
131.201 +
131.202 + @Override
131.203 + public void writeStartResultSet(ColumnsHeader header) {
131.204 + super.writeStartResultSet(header);
131.205 + resultSetCounter++;
131.206 + printEmptyElement(qname("hr"), null);
131.207 + printTextElement(qname("h3"), null, "Result set #" + resultSetCounter);
131.208 + printStartElement(qname("table"));
131.209 + printStartElement(qname("thead"));
131.210 + printStartElement(qname("tr"));
131.211 + for (ColumnDescriptor cd : header.getColumnDescriptors()) {
131.212 + // TODO: type
131.213 + printTextElement(qname("td"), null, cd.getLabel());
131.214 + }
131.215 + printEndElement();
131.216 + printEndElement();
131.217 +
131.218 + printStartElement(qname("tbody"));
131.219 + }
131.220 +
131.221 + @Override
131.222 + public void writeEndResultSet() {
131.223 + super.writeEndResultSet();
131.224 + printEndElement();
131.225 + printEndElement();
131.226 + printTextElement(qname("p"), null, "Record count: " + getCurrentRowCount());
131.227 + }
131.228 +
131.229 + @Override
131.230 + public void writeStartRow() {
131.231 + super.writeStartRow();
131.232 + printStartElement(qname("tr"));
131.233 + }
131.234 +
131.235 + @Override
131.236 + public void writeColumnValue(Object value) {
131.237 + super.writeColumnValue(value);
131.238 + printTableData(value);
131.239 + }
131.240 +
131.241 + @Override
131.242 + public void writeEndRow() {
131.243 + super.writeEndRow();
131.244 + printEndElement();
131.245 + }
131.246 +
131.247 + @Override
131.248 + public void writeStartStatement() {
131.249 + super.writeStartStatement();
131.250 + statementCounter++;
131.251 + printEmptyElement(qname("hr"), null);
131.252 + printTextElement(qname("h2"), null, "SQL statement #" + statementCounter);
131.253 + resultSetCounter = 0;
131.254 + updatesResultCounter = 0;
131.255 + }
131.256 +
131.257 + @Override
131.258 + public void writeUpdatesResult(int updatedRowsCount) {
131.259 + super.writeUpdatesResult(updatedRowsCount);
131.260 + updatesResultCounter++;
131.261 + printEmptyElement(qname("hr"), null);
131.262 + printTextElement(qname("h3"), null, "Updates result #" + updatesResultCounter);
131.263 + printTextElement(qname("p"), null, "Updated rows: " + updatedRowsCount);
131.264 + }
131.265 +}
132.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
132.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/formatting/XmlFormatter.java Mon Mar 04 20:15:24 2019 +0100
132.3 @@ -0,0 +1,245 @@
132.4 +/**
132.5 + * SQL-DK
132.6 + * Copyright © 2013 František Kučera (frantovo.cz)
132.7 + *
132.8 + * This program is free software: you can redistribute it and/or modify
132.9 + * it under the terms of the GNU General Public License as published by
132.10 + * the Free Software Foundation, either version 3 of the License, or
132.11 + * (at your option) any later version.
132.12 + *
132.13 + * This program is distributed in the hope that it will be useful,
132.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
132.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
132.16 + * GNU General Public License for more details.
132.17 + *
132.18 + * You should have received a copy of the GNU General Public License
132.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
132.20 + */
132.21 +package info.globalcode.sql.dk.formatting;
132.22 +
132.23 +import info.globalcode.sql.dk.Parameter;
132.24 +import info.globalcode.sql.dk.Xmlns;
132.25 +import info.globalcode.sql.dk.configuration.DatabaseDefinition;
132.26 +import static info.globalcode.sql.dk.Functions.notNull;
132.27 +import info.globalcode.sql.dk.NamedParameter;
132.28 +import info.globalcode.sql.dk.configuration.PropertyDeclaration;
132.29 +import static info.globalcode.sql.dk.formatting.AbstractXmlFormatter.qname;
132.30 +import java.sql.Array;
132.31 +import java.sql.ResultSet;
132.32 +import java.sql.SQLException;
132.33 +import java.sql.SQLXML;
132.34 +import java.util.ArrayList;
132.35 +import java.util.LinkedHashMap;
132.36 +import java.util.List;
132.37 +import java.util.Map;
132.38 +import java.util.logging.Level;
132.39 +import java.util.logging.Logger;
132.40 +import javax.xml.namespace.QName;
132.41 +
132.42 +/**
132.43 + * <p>
132.44 + * Prints machine-readable output – XML document containing resultsets and updates count. Good
132.45 + * choice for further processing – e.g. XSL transformation.</p>
132.46 + *
132.47 + * <p>
132.48 + * TODO: XSD</p>
132.49 + *
132.50 + * @author Ing. František Kučera (frantovo.cz)
132.51 + */
132.52 +@PropertyDeclaration(name = XmlFormatter.PROPERTY_LABELED_COLUMNS, defaultValue = "false", type = Boolean.class, description = "whether to add 'label' attribute to each 'column' element")
132.53 +public class XmlFormatter extends AbstractXmlFormatter {
132.54 +
132.55 + public static final String NAME = "xml"; // bash-completion:formatter
132.56 + public static final String PROPERTY_LABELED_COLUMNS = "labeledColumns";
132.57 + private static final Logger log = Logger.getLogger(XmlFormatter.class.getName());
132.58 + private final boolean labeledColumns;
132.59 +
132.60 + public XmlFormatter(FormatterContext formatterContext) {
132.61 + super(formatterContext);
132.62 + labeledColumns = formatterContext.getProperties().getBoolean(PROPERTY_LABELED_COLUMNS, false);
132.63 + }
132.64 +
132.65 + @Override
132.66 + public void writeStartBatch() {
132.67 + super.writeStartBatch();
132.68 + printStartDocument();
132.69 + printStartElement(qname("batchResult"), singleAttribute(qname("xmlns"), Xmlns.BATCH_RESULT));
132.70 + }
132.71 +
132.72 + @Override
132.73 + public void writeEndBatch() {
132.74 + super.writeEndBatch();
132.75 + printEndElement();
132.76 + printEndDocument();
132.77 + }
132.78 +
132.79 + @Override
132.80 + public void writeStartDatabase(DatabaseDefinition databaseDefinition) {
132.81 + super.writeStartDatabase(databaseDefinition);
132.82 + Map<QName, String> attributes = databaseDefinition.getName() == null ? null : singleAttribute(qname("name"), databaseDefinition.getName());
132.83 + printStartElement(qname("database"), attributes);
132.84 + }
132.85 +
132.86 + @Override
132.87 + public void writeEndDatabase() {
132.88 + super.writeEndDatabase();
132.89 + printEndElement();
132.90 + }
132.91 +
132.92 + @Override
132.93 + public void writeStartStatement() {
132.94 + super.writeStartStatement();
132.95 + printStartElement(qname("statement"));
132.96 + }
132.97 +
132.98 + @Override
132.99 + public void writeEndStatement() {
132.100 + super.writeEndStatement();
132.101 + printEndElement();
132.102 + }
132.103 +
132.104 + @Override
132.105 + public void writeQuery(String sql) {
132.106 + super.writeQuery(sql);
132.107 + printTextElement(qname("sql"), null, sql);
132.108 + }
132.109 +
132.110 + @Override
132.111 + public void writeParameters(List<? extends Parameter> parameters) {
132.112 + super.writeParameters(parameters);
132.113 +
132.114 + for (Parameter p : notNull(parameters)) {
132.115 +
132.116 + Map<QName, String> attributes = new LinkedHashMap<>(2);
132.117 + if (p instanceof NamedParameter) {
132.118 + attributes.put(qname("name"), ((NamedParameter) p).getName());
132.119 + }
132.120 + attributes.put(qname("type"), p.getType().name());
132.121 +
132.122 + printTextElement(qname("parameter"), attributes, String.valueOf(p.getValue()));
132.123 + }
132.124 +
132.125 + }
132.126 +
132.127 + @Override
132.128 + public void writeStartResultSet(ColumnsHeader header) {
132.129 + super.writeStartResultSet(header);
132.130 + printStartElement(qname("resultSet"));
132.131 +
132.132 + for (ColumnDescriptor cd : header.getColumnDescriptors()) {
132.133 + Map<QName, String> attributes = new LinkedHashMap<>(4);
132.134 + attributes.put(qname("label"), cd.getLabel());
132.135 + attributes.put(qname("name"), cd.getName());
132.136 + attributes.put(qname("typeName"), cd.getTypeName());
132.137 + attributes.put(qname("type"), String.valueOf(cd.getType()));
132.138 + printEmptyElement(qname("columnHeader"), attributes);
132.139 + }
132.140 + }
132.141 +
132.142 + @Override
132.143 + public void writeEndResultSet() {
132.144 + super.writeEndResultSet();
132.145 + printEndElement();
132.146 + }
132.147 +
132.148 + @Override
132.149 + public void writeStartRow() {
132.150 + super.writeStartRow();
132.151 + printStartElement(qname("row"));
132.152 + }
132.153 +
132.154 + @Override
132.155 + public void writeColumnValue(Object value) {
132.156 + super.writeColumnValue(value);
132.157 +
132.158 + Map<QName, String> attributes = null;
132.159 + if (labeledColumns) {
132.160 + attributes = new LinkedHashMap<>(2);
132.161 + attributes.put(qname("label"), getCurrentColumnsHeader().getColumnDescriptors().get(getCurrentColumnsCount() - 1).getLabel());
132.162 + }
132.163 +
132.164 + if (value == null) {
132.165 + if (attributes == null) {
132.166 + attributes = new LinkedHashMap<>(2);
132.167 + }
132.168 + attributes.put(qname("null"), "true");
132.169 + printEmptyElement(qname("column"), attributes);
132.170 + } else if (value instanceof Array) {
132.171 +
132.172 + Array sqlArray = (Array) value;
132.173 + try {
132.174 + Object[] array = (Object[]) sqlArray.getArray();
132.175 + printStartElement(qname("column"), attributes);
132.176 + printArray(array);
132.177 + printEndElement();
132.178 + } catch (SQLException e) {
132.179 + // FIXME: rewrite array formatting, remember array mode, don't try sqlArray.getArray() again and again if it has failed
132.180 + log.log(Level.SEVERE, "Unable to format array", e);
132.181 + try {
132.182 + ResultSet arrayResultSet = sqlArray.getResultSet();
132.183 + //int columnCount = arrayResultSet.getMetaData().getColumnCount();
132.184 + ArrayList<Object> arrayList = new ArrayList<>();
132.185 + while (arrayResultSet.next()) {
132.186 + arrayList.add(arrayResultSet.getObject(2));
132.187 + // for (int i = 1; i <= columnCount; i++) {
132.188 + // log.log(Level.INFO, "Array column {0} = {1}", new Object[]{i, arrayResultSet.getObject(i)});
132.189 + // }
132.190 + }
132.191 +
132.192 + printStartElement(qname("column"), attributes);
132.193 + // FIXME: instanceof SQLXML, see below
132.194 + printArray(arrayList.toArray());
132.195 + printEndElement();
132.196 +
132.197 + } catch (SQLException e2) {
132.198 + // FIXME: fix logging, error recovery
132.199 + log.log(Level.SEVERE, "Second level fuck up !!!", e2);
132.200 + }
132.201 +
132.202 + writeColumnValue(String.valueOf(value));
132.203 + }
132.204 +
132.205 + } else if (value instanceof SQLXML) { // FIXME: move to separate method, to AbstractFormatter?
132.206 + SQLXML xml = (SQLXML) value;
132.207 + // TODO: parse DOM/SAX and transplant XML, don't escape (optional)
132.208 + try {
132.209 + printTextElement(qname("column"), attributes, xml.getString());
132.210 + } catch (SQLException e) {
132.211 + log.log(Level.SEVERE, "Unable to format XML", e);
132.212 + writeColumnValue(String.valueOf(value));
132.213 + }
132.214 + } else {
132.215 + printTextElement(qname("column"), attributes, toString(value));
132.216 + }
132.217 + }
132.218 +
132.219 + private void printArray(Object[] array) {
132.220 + printStartElement(qname("array"));
132.221 + for (Object o : array) {
132.222 + if (o instanceof Object[]) {
132.223 + printStartElement(qname("item"));
132.224 + printArray((Object[]) o);
132.225 + printEndElement();
132.226 + } else {
132.227 + printTextElement(qname("item"), null, String.valueOf(o));
132.228 + }
132.229 + }
132.230 + printEndElement();
132.231 + }
132.232 +
132.233 + @Override
132.234 + public void writeEndRow() {
132.235 + super.writeEndRow();
132.236 + printEndElement();
132.237 + }
132.238 +
132.239 + @Override
132.240 + public void writeUpdatesResult(int updatedRowsCount) {
132.241 + super.writeUpdatesResult(updatedRowsCount);
132.242 + printTextElement(qname("updatedRows"), null, String.valueOf(updatedRowsCount));
132.243 + }
132.244 +
132.245 + protected String toString(Object value) {
132.246 + return String.valueOf(value);
132.247 + }
132.248 +}
133.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
133.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/jmx/ConnectionManagement.java Mon Mar 04 20:15:24 2019 +0100
133.3 @@ -0,0 +1,97 @@
133.4 +/**
133.5 + * SQL-DK
133.6 + * Copyright © 2014 František Kučera (frantovo.cz)
133.7 + *
133.8 + * This program is free software: you can redistribute it and/or modify
133.9 + * it under the terms of the GNU General Public License as published by
133.10 + * the Free Software Foundation, either version 3 of the License, or
133.11 + * (at your option) any later version.
133.12 + *
133.13 + * This program is distributed in the hope that it will be useful,
133.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
133.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
133.16 + * GNU General Public License for more details.
133.17 + *
133.18 + * You should have received a copy of the GNU General Public License
133.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
133.20 + */
133.21 +package info.globalcode.sql.dk.jmx;
133.22 +
133.23 +import java.util.EnumMap;
133.24 +import java.util.Map;
133.25 +
133.26 +/**
133.27 + * JMX management bean for progress reporting.
133.28 + *
133.29 + * @author Ing. František Kučera (frantovo.cz)
133.30 + */
133.31 +public class ConnectionManagement implements ConnectionManagementMBean {
133.32 +
133.33 + private final String databaseName;
133.34 + private final Map<COUNTER, Integer> counters = new EnumMap(COUNTER.class);
133.35 +
133.36 + public ConnectionManagement(String databaseName) {
133.37 + this.databaseName = databaseName;
133.38 + for (COUNTER c : COUNTER.values()) {
133.39 + counters.put(c, 0);
133.40 + }
133.41 + }
133.42 +
133.43 + public enum COUNTER {
133.44 +
133.45 + COMMAND,
133.46 + RECORD_CURRENT,
133.47 + RECORD_TOTAL
133.48 + };
133.49 +
133.50 + public void incrementCounter(COUNTER counter) {
133.51 + synchronized (counters) {
133.52 + int old = counters.get(counter);
133.53 + counters.put(counter, old + 1);
133.54 + }
133.55 + }
133.56 +
133.57 + public void resetCounter(COUNTER counter) {
133.58 + synchronized (counters) {
133.59 + counters.put(counter, 0);
133.60 + }
133.61 + }
133.62 +
133.63 + public static void incrementCounter(ConnectionManagement mbean, COUNTER counter) {
133.64 + if (mbean != null) {
133.65 + mbean.incrementCounter(counter);
133.66 + }
133.67 + }
133.68 +
133.69 + public static void resetCounter(ConnectionManagement mbean, COUNTER counter) {
133.70 + if (mbean != null) {
133.71 + mbean.resetCounter(counter);
133.72 + }
133.73 + }
133.74 +
133.75 + @Override
133.76 + public String getDatabaseName() {
133.77 + return databaseName;
133.78 + }
133.79 +
133.80 + @Override
133.81 + public int getCommandCount() {
133.82 + synchronized (counters) {
133.83 + return counters.get(COUNTER.COMMAND);
133.84 + }
133.85 + }
133.86 +
133.87 + @Override
133.88 + public int getCurrentRecordCount() {
133.89 + synchronized (counters) {
133.90 + return counters.get(COUNTER.RECORD_CURRENT);
133.91 + }
133.92 + }
133.93 +
133.94 + @Override
133.95 + public int getTotalRecordCount() {
133.96 + synchronized (counters) {
133.97 + return counters.get(COUNTER.RECORD_TOTAL);
133.98 + }
133.99 + }
133.100 +}
134.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
134.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/jmx/ConnectionManagementMBean.java Mon Mar 04 20:15:24 2019 +0100
134.3 @@ -0,0 +1,34 @@
134.4 +/**
134.5 + * SQL-DK
134.6 + * Copyright © 2014 František Kučera (frantovo.cz)
134.7 + *
134.8 + * This program is free software: you can redistribute it and/or modify
134.9 + * it under the terms of the GNU General Public License as published by
134.10 + * the Free Software Foundation, either version 3 of the License, or
134.11 + * (at your option) any later version.
134.12 + *
134.13 + * This program is distributed in the hope that it will be useful,
134.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
134.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134.16 + * GNU General Public License for more details.
134.17 + *
134.18 + * You should have received a copy of the GNU General Public License
134.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
134.20 + */
134.21 +package info.globalcode.sql.dk.jmx;
134.22 +
134.23 +/**
134.24 + *
134.25 + * @author Ing. František Kučera (frantovo.cz)
134.26 + */
134.27 +public interface ConnectionManagementMBean {
134.28 +
134.29 + public String getDatabaseName();
134.30 +
134.31 + public int getCommandCount();
134.32 +
134.33 + public int getCurrentRecordCount();
134.34 +
134.35 + public int getTotalRecordCount();
134.36 +
134.37 +}
135.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
135.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/jmx/ManagementUtils.java Mon Mar 04 20:15:24 2019 +0100
135.3 @@ -0,0 +1,68 @@
135.4 +/**
135.5 + * SQL-DK
135.6 + * Copyright © 2014 František Kučera (frantovo.cz)
135.7 + *
135.8 + * This program is free software: you can redistribute it and/or modify
135.9 + * it under the terms of the GNU General Public License as published by
135.10 + * the Free Software Foundation, either version 3 of the License, or
135.11 + * (at your option) any later version.
135.12 + *
135.13 + * This program is distributed in the hope that it will be useful,
135.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
135.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
135.16 + * GNU General Public License for more details.
135.17 + *
135.18 + * You should have received a copy of the GNU General Public License
135.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
135.20 + */
135.21 +package info.globalcode.sql.dk.jmx;
135.22 +
135.23 +import java.lang.management.ManagementFactory;
135.24 +import java.util.Hashtable;
135.25 +import java.util.logging.Level;
135.26 +import java.util.logging.Logger;
135.27 +import javax.management.MBeanServer;
135.28 +import javax.management.ObjectName;
135.29 +
135.30 +/**
135.31 + *
135.32 + * @author Ing. František Kučera (frantovo.cz)
135.33 + */
135.34 +public class ManagementUtils {
135.35 +
135.36 + private static final Logger log = Logger.getLogger(ManagementUtils.class.getName());
135.37 + public static final String DEFAULT_CONNECTION_JMX_NAME = "main";
135.38 +
135.39 + /**
135.40 + * @see #registerMBean(java.lang.String, java.lang.String) with default JMX name
135.41 + */
135.42 + public static ConnectionManagement registerMBean(String dbName) {
135.43 + return registerMBean(dbName, DEFAULT_CONNECTION_JMX_NAME);
135.44 + }
135.45 +
135.46 + /**
135.47 + *
135.48 + * @param dbName database name
135.49 + * @param jmxName name of JMX bean
135.50 + * @return registered JMX bean | or null if registration fails (should not)
135.51 + */
135.52 + public static ConnectionManagement registerMBean(String dbName, String jmxName) {
135.53 + try {
135.54 + ConnectionManagement mbean = new ConnectionManagement(dbName);
135.55 + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
135.56 + Hashtable<String, String> objectProperties = new Hashtable<>();
135.57 + objectProperties.put("type", "Connection");
135.58 + objectProperties.put("name", jmxName);
135.59 + ObjectName objectName = new ObjectName("info.globalcode.sql.dk", objectProperties);
135.60 + mbs.registerMBean(mbean, objectName);
135.61 + log.log(Level.FINE, "JMX MBean was registered as: {0}", objectName);
135.62 + return mbean;
135.63 + } catch (Exception e) {
135.64 + log.log(Level.WARNING, "Unable to register JMX MBean", e);
135.65 + return null;
135.66 + }
135.67 + }
135.68 +
135.69 + private ManagementUtils() {
135.70 + }
135.71 +}
136.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/logging/ColorfulConsoleFormatter.java Mon Mar 04 20:15:24 2019 +0100
136.3 @@ -0,0 +1,97 @@
136.4 +/**
136.5 + * SQL-DK
136.6 + * Copyright © 2013 František Kučera (frantovo.cz)
136.7 + *
136.8 + * This program is free software: you can redistribute it and/or modify
136.9 + * it under the terms of the GNU General Public License as published by
136.10 + * the Free Software Foundation, either version 3 of the License, or
136.11 + * (at your option) any later version.
136.12 + *
136.13 + * This program is distributed in the hope that it will be useful,
136.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
136.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
136.16 + * GNU General Public License for more details.
136.17 + *
136.18 + * You should have received a copy of the GNU General Public License
136.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
136.20 + */
136.21 +package info.globalcode.sql.dk.logging;
136.22 +
136.23 +import info.globalcode.sql.dk.ColorfulPrintWriter;
136.24 +import static info.globalcode.sql.dk.ColorfulPrintWriter.TerminalColor;
136.25 +import static info.globalcode.sql.dk.ColorfulPrintWriter.TerminalStyle;
136.26 +import static info.globalcode.sql.dk.Functions.rpad;
136.27 +import java.io.StringWriter;
136.28 +import java.util.logging.Formatter;
136.29 +import java.util.logging.Level;
136.30 +import java.util.logging.LogRecord;
136.31 +
136.32 +/**
136.33 + * For console/terminal log output. Log messages are printed in brief and colorful form.
136.34 + *
136.35 + * @author Ing. František Kučera (frantovo.cz)
136.36 + */
136.37 +public class ColorfulConsoleFormatter extends Formatter {
136.38 +
136.39 + private boolean printStacktrace = false;
136.40 +
136.41 + @Override
136.42 + public String format(LogRecord r) {
136.43 + StringWriter sw = new StringWriter();
136.44 + try (ColorfulPrintWriter out = new ColorfulPrintWriter(sw)) {
136.45 + printLevel(out, r.getLevel());
136.46 + printMessage(out, r);
136.47 + printThrowable(out, r);
136.48 + out.println();
136.49 + }
136.50 + return sw.toString();
136.51 + }
136.52 +
136.53 + private void printLevel(ColorfulPrintWriter out, Level l) {
136.54 + TerminalColor color = TerminalColor.Magenta;
136.55 +
136.56 + if (l == Level.SEVERE) {
136.57 + color = TerminalColor.Red;
136.58 + } else if (l == Level.WARNING) {
136.59 + color = TerminalColor.Yellow;
136.60 + }
136.61 +
136.62 + out.print(color, rpad(l.getLocalizedName() + ": ", 10));
136.63 + }
136.64 +
136.65 + private void printMessage(ColorfulPrintWriter out, LogRecord r) {
136.66 + out.print(formatMessage(r));
136.67 + }
136.68 +
136.69 + private void printThrowable(ColorfulPrintWriter out, LogRecord r) {
136.70 + Throwable t = r.getThrown();
136.71 + if (t != null) {
136.72 + out.print(": ");
136.73 + out.print(TerminalColor.Red, t.getClass().getSimpleName());
136.74 + String message = t.getLocalizedMessage();
136.75 + if (message != null) {
136.76 + out.print(": ");
136.77 + if (printStacktrace) {
136.78 + out.print(message);
136.79 + } else {
136.80 + out.print(message.replaceAll("\\n", " "));
136.81 + }
136.82 + }
136.83 + if (printStacktrace) {
136.84 + out.println();
136.85 + out.setForegroundColor(TerminalColor.Yellow);
136.86 + out.setStyle(TerminalStyle.Dim);
136.87 + t.printStackTrace(out);
136.88 + out.resetAll();
136.89 + }
136.90 + }
136.91 + }
136.92 +
136.93 + public boolean isPrintStacktrace() {
136.94 + return printStacktrace;
136.95 + }
136.96 +
136.97 + public void setPrintStacktrace(boolean printStacktrace) {
136.98 + this.printStacktrace = printStacktrace;
136.99 + }
136.100 +}
137.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
137.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/logging/LoggerInitializer.java Mon Mar 04 20:15:24 2019 +0100
137.3 @@ -0,0 +1,78 @@
137.4 +/**
137.5 + * SQL-DK
137.6 + * Copyright © 2013 František Kučera (frantovo.cz)
137.7 + *
137.8 + * This program is free software: you can redistribute it and/or modify
137.9 + * it under the terms of the GNU General Public License as published by
137.10 + * the Free Software Foundation, either version 3 of the License, or
137.11 + * (at your option) any later version.
137.12 + *
137.13 + * This program is distributed in the hope that it will be useful,
137.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
137.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
137.16 + * GNU General Public License for more details.
137.17 + *
137.18 + * You should have received a copy of the GNU General Public License
137.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
137.20 + */
137.21 +package info.globalcode.sql.dk.logging;
137.22 +
137.23 +import info.globalcode.sql.dk.Constants;
137.24 +import java.util.logging.ConsoleHandler;
137.25 +import java.util.logging.Handler;
137.26 +import java.util.logging.Level;
137.27 +import java.util.logging.Logger;
137.28 +
137.29 +/**
137.30 + * Configures logging subsystem.
137.31 + * Usage: java -Djava.util.logging.config.class=info.globalcode.sql.dk.logging.LoggerInitializer …
137.32 + *
137.33 + * @author Ing. František Kučera (frantovo.cz)
137.34 + */
137.35 +public class LoggerInitializer {
137.36 +
137.37 + private static final Logger log = Logger.getLogger(LoggerInitializer.class.getName());
137.38 + public static final String LEVEL_PROPERTY = LoggerInitializer.class.getName() + ".level";
137.39 + private static final Level DEFAULT_LEVEL = Level.INFO;
137.40 +
137.41 + public LoggerInitializer() {
137.42 + Logger logger = Logger.getLogger(Constants.JAVA_PACKAGE);
137.43 + ConsoleHandler handler = new ConsoleHandler();
137.44 + ColorfulConsoleFormatter formatter = new ColorfulConsoleFormatter();
137.45 +
137.46 + logger.addHandler(handler);
137.47 + handler.setFormatter(formatter);
137.48 +
137.49 + setLevel(logger, handler, formatter);
137.50 +
137.51 +
137.52 + /**
137.53 + * TODO: optional FileHandler – detailed logs in file in ~/sql-dk/log/…
137.54 + */
137.55 + }
137.56 +
137.57 + private void setLevel(Logger logger, Handler handler, ColorfulConsoleFormatter formatter) {
137.58 + boolean levelParseError = false;
137.59 + Level level;
137.60 + String cliLevel = System.getProperty(LEVEL_PROPERTY);
137.61 + if (cliLevel == null) {
137.62 + level = DEFAULT_LEVEL;
137.63 + } else {
137.64 + try {
137.65 + level = Level.parse(cliLevel);
137.66 + } catch (IllegalArgumentException e) {
137.67 + level = DEFAULT_LEVEL;
137.68 + levelParseError = true;
137.69 + }
137.70 + }
137.71 +
137.72 + handler.setLevel(level);
137.73 + logger.setLevel(level);
137.74 +
137.75 + if (levelParseError) {
137.76 + log.log(Level.WARNING, "Invalid logging level „{0}“ specified in „{1}“ → using default level „{2}“", new Object[]{cliLevel, LEVEL_PROPERTY, DEFAULT_LEVEL});
137.77 + }
137.78 +
137.79 + formatter.setPrintStacktrace(level.intValue() < Level.INFO.intValue());
137.80 + }
137.81 +}
138.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
138.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/logging/LoggerProducer.java Mon Mar 04 20:15:24 2019 +0100
138.3 @@ -0,0 +1,36 @@
138.4 +/**
138.5 + * SQL-DK
138.6 + * Copyright © 2015 František Kučera (frantovo.cz)
138.7 + *
138.8 + * This program is free software: you can redistribute it and/or modify
138.9 + * it under the terms of the GNU General Public License as published by
138.10 + * the Free Software Foundation, either version 3 of the License, or
138.11 + * (at your option) any later version.
138.12 + *
138.13 + * This program is distributed in the hope that it will be useful,
138.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
138.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
138.16 + * GNU General Public License for more details.
138.17 + *
138.18 + * You should have received a copy of the GNU General Public License
138.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
138.20 + */
138.21 +package info.globalcode.sql.dk.logging;
138.22 +
138.23 +import java.util.logging.Logger;
138.24 +
138.25 +/**
138.26 + *
138.27 + * @author Ing. František Kučera (frantovo.cz)
138.28 + */
138.29 +public class LoggerProducer {
138.30 +
138.31 + /**
138.32 + * @return created logger for the caller class
138.33 + */
138.34 + public static Logger getLogger() {
138.35 + String className = Thread.currentThread().getStackTrace()[2].getClassName();
138.36 + return Logger.getLogger(className);
138.37 + }
138.38 +
138.39 +}
139.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
139.2 +++ b/java/sql-dk/src/main/resources/info/globalcode/sql/dk/configuration/jaxb.index Mon Mar 04 20:15:24 2019 +0100
139.3 @@ -0,0 +1,1 @@
139.4 +Configuration
139.5 \ No newline at end of file
140.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
140.2 +++ b/java/sql-dk/src/main/resources/info/globalcode/sql/dk/example-config.xml Mon Mar 04 20:15:24 2019 +0100
140.3 @@ -0,0 +1,1 @@
140.4 +../../../../../../../../../xml/config.xml
140.5 \ No newline at end of file
141.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
141.2 +++ b/java/sql-dk/src/main/resources/info/globalcode/sql/dk/formatter/XhtmlFormatter.css Mon Mar 04 20:15:24 2019 +0100
141.3 @@ -0,0 +1,54 @@
141.4 +body {
141.5 + font-family: sans-serif;
141.6 + font-size: 16px;
141.7 + padding-left: 16px;
141.8 + padding-right: 16px;
141.9 +}
141.10 +
141.11 +pre {
141.12 + background-color: #ddd;
141.13 + padding: 6px;
141.14 + border-radius: 4px;
141.15 + overflow: auto;
141.16 +
141.17 + -moz-tab-size: 4;
141.18 + -o-tab-size: 4;
141.19 + tab-size: 4;
141.20 +}
141.21 +
141.22 +table {
141.23 + border-collapse:collapse;
141.24 + box-shadow: 3px 3px 3px grey;
141.25 + margin-top: 10px;
141.26 + margin-bottom: 20px;
141.27 +}
141.28 +td, th {
141.29 + border: 1px solid black;
141.30 + padding-top: 4px;
141.31 + padding-bottom: 4px;
141.32 + padding-left: 6px;
141.33 + padding-right: 6px;
141.34 + font-weight: normal;
141.35 +}
141.36 +td.number {
141.37 + text-align: right;
141.38 +}
141.39 +td.boolean {
141.40 + text-align: right;
141.41 +}
141.42 +thead tr {
141.43 + background: #ddd;
141.44 + color:black;
141.45 +}
141.46 +tbody tr:hover {
141.47 + background-color: #eee;
141.48 + color:black;
141.49 +}
141.50 +
141.51 +table ul {
141.52 + margin: 0px;
141.53 +}
141.54 +
141.55 +table li {
141.56 + padding-right: 10px;
141.57 +}
142.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
142.2 +++ b/java/sql-dk/src/main/resources/info/globalcode/sql/dk/license.txt Mon Mar 04 20:15:24 2019 +0100
142.3 @@ -0,0 +1,1 @@
142.4 +../../../../../../../../../license/gpl.txt
142.5 \ No newline at end of file
143.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
143.2 +++ b/java/sql-dk/src/test/java/info/globalcode/sql/dk/CLIParserTest.java Mon Mar 04 20:15:24 2019 +0100
143.3 @@ -0,0 +1,195 @@
143.4 +/**
143.5 + * SQL-DK
143.6 + * Copyright © 2013 František Kučera (frantovo.cz)
143.7 + *
143.8 + * This program is free software: you can redistribute it and/or modify
143.9 + * it under the terms of the GNU General Public License as published by
143.10 + * the Free Software Foundation, either version 3 of the License, or
143.11 + * (at your option) any later version.
143.12 + *
143.13 + * This program is distributed in the hope that it will be useful,
143.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
143.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143.16 + * GNU General Public License for more details.
143.17 + *
143.18 + * You should have received a copy of the GNU General Public License
143.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
143.20 + */
143.21 +package info.globalcode.sql.dk;
143.22 +
143.23 +import info.globalcode.sql.dk.CLIParser.Tokens;
143.24 +import static info.globalcode.sql.dk.CLIParser.TYPE_NAME_SEPARATOR;
143.25 +import info.globalcode.sql.dk.InfoLister.InfoType;
143.26 +import java.io.ByteArrayInputStream;
143.27 +import java.util.Collection;
143.28 +import static org.testng.Assert.*;
143.29 +import org.testng.annotations.BeforeMethod;
143.30 +import org.testng.annotations.Test;
143.31 +
143.32 +/**
143.33 + *
143.34 + * @author Ing. František Kučera (frantovo.cz)
143.35 + */
143.36 +public class CLIParserTest {
143.37 +
143.38 + private static final String DATABASE_NAME_1 = "some database 1";
143.39 + private static final String SQL_1 = "SELECT * FROM table1";
143.40 + private static final String DATA_1 = "aaa";
143.41 + private static final String DATA_2 = "bbb";
143.42 + private static final String DATA_3 = "ccc";
143.43 + private static final String NAME_1 = "param1";
143.44 + private static final String NAME_2 = "param2";
143.45 + private static final String NAME_3 = "param3";
143.46 + private CLIParser parser;
143.47 +
143.48 + @BeforeMethod
143.49 + public void setUpMethod() throws Exception {
143.50 + parser = new CLIParser();
143.51 + }
143.52 +
143.53 + private CLIOptions parseOptions(String[] args) throws CLIParserException {
143.54 + return parser.parseOptions(args, new ByteArrayInputStream("".getBytes()));
143.55 + }
143.56 +
143.57 + @Test
143.58 + public void testParseOptions_QueryNow_NoParams() throws InvalidOptionsException, CLIParserException {
143.59 + String[] args = new String[]{
143.60 + Tokens.DB, DATABASE_NAME_1,
143.61 + Tokens.SQL, SQL_1};
143.62 + CLIOptions options = parseOptions(args);
143.63 + options.validate();
143.64 +
143.65 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.66 + assertEquals(options.getSql(), SQL_1);
143.67 + assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
143.68 + assertTrue(options.getNamedParameters().isEmpty(), "Named parameters should be empty.");
143.69 + assertTrue(options.getNumberedParameters().isEmpty(), "Numbered parameters should be empty.");
143.70 + }
143.71 +
143.72 + @Test
143.73 + public void testParseOptions_QueryNow_Numbered() throws InvalidOptionsException, CLIParserException {
143.74 + String[] args = new String[]{
143.75 + Tokens.DB, DATABASE_NAME_1,
143.76 + Tokens.SQL, SQL_1,
143.77 + Tokens.DATA, DATA_1, DATA_2, DATA_3};
143.78 + CLIOptions options = parseOptions(args);
143.79 + options.validate();
143.80 +
143.81 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.82 + assertEquals(options.getSql(), SQL_1);
143.83 + assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
143.84 + assertEquals(options.getNumberedParameters().size(), 3);
143.85 + assertEquals(options.getNumberedParameters().get(0).getValue(), DATA_1);
143.86 + assertEquals(options.getNumberedParameters().get(1).getValue(), DATA_2);
143.87 + assertEquals(options.getNumberedParameters().get(2).getValue(), DATA_3);
143.88 + assertEquals(options.getNumberedParameters().get(0).getType(), Parameter.DEFAULT_TYPE);
143.89 + assertEquals(options.getNumberedParameters().get(1).getType(), Parameter.DEFAULT_TYPE);
143.90 + assertEquals(options.getNumberedParameters().get(2).getType(), Parameter.DEFAULT_TYPE);
143.91 + }
143.92 +
143.93 + @Test
143.94 + public void testParseOptions_QueryNow_Numbered_withTypes() throws InvalidOptionsException, CLIParserException {
143.95 + String[] args = new String[]{
143.96 + Tokens.DB, DATABASE_NAME_1,
143.97 + Tokens.SQL, SQL_1,
143.98 + Tokens.TYPES, " INTEGER,VARCHAR, BOOLEAN",
143.99 + Tokens.DATA, DATA_1, DATA_2, DATA_3};
143.100 + CLIOptions options = parseOptions(args);
143.101 + options.validate();
143.102 +
143.103 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.104 + assertEquals(options.getSql(), SQL_1);
143.105 + assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
143.106 + assertEquals(options.getNumberedParameters().size(), 3);
143.107 + assertEquals(options.getNumberedParameters().get(0).getValue(), DATA_1);
143.108 + assertEquals(options.getNumberedParameters().get(1).getValue(), DATA_2);
143.109 + assertEquals(options.getNumberedParameters().get(2).getValue(), DATA_3);
143.110 + assertEquals(options.getNumberedParameters().get(0).getType(), SQLType.INTEGER);
143.111 + assertEquals(options.getNumberedParameters().get(1).getType(), SQLType.VARCHAR);
143.112 + assertEquals(options.getNumberedParameters().get(2).getType(), SQLType.BOOLEAN);
143.113 + }
143.114 +
143.115 + @Test
143.116 + public void testParseOptions_QueryNow_Named() throws InvalidOptionsException, CLIParserException {
143.117 + String[] args = new String[]{
143.118 + Tokens.DB, DATABASE_NAME_1,
143.119 + Tokens.SQL, SQL_1,
143.120 + Tokens.DATA_NAMED, NAME_1, DATA_1, NAME_2, DATA_2, NAME_3, DATA_3};
143.121 + CLIOptions options = parseOptions(args);
143.122 + options.validate();
143.123 +
143.124 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.125 + assertEquals(options.getSql(), SQL_1);
143.126 + assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
143.127 + assertEquals(options.getNamedParameters().size(), 3);
143.128 + assertNamedParameter(options.getNamedParameters(), NAME_1, DATA_1, Parameter.DEFAULT_TYPE);
143.129 + assertNamedParameter(options.getNamedParameters(), NAME_2, DATA_2, Parameter.DEFAULT_TYPE);
143.130 + assertNamedParameter(options.getNamedParameters(), NAME_3, DATA_3, Parameter.DEFAULT_TYPE);
143.131 + }
143.132 +
143.133 + @Test
143.134 + public void testParseOptions_QueryNow_Named_withTypes() throws InvalidOptionsException, CLIParserException {
143.135 + String[] args = new String[]{
143.136 + Tokens.DB, DATABASE_NAME_1,
143.137 + Tokens.SQL, SQL_1,
143.138 + Tokens.NAME_PREFIX, "$",
143.139 + Tokens.TYPES, " " + NAME_1 + TYPE_NAME_SEPARATOR + "INTEGER" + "," + NAME_3 + TYPE_NAME_SEPARATOR + "BOOLEAN",
143.140 + Tokens.DATA_NAMED, NAME_1, DATA_1, NAME_2, DATA_2, NAME_3, DATA_3};
143.141 + CLIOptions options = parseOptions(args);
143.142 + options.validate();
143.143 +
143.144 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.145 + assertEquals(options.getSql(), SQL_1);
143.146 + assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
143.147 + assertEquals(options.getNamedParameters().size(), 3);
143.148 + assertNamedParameter(options.getNamedParameters(), NAME_1, DATA_1, SQLType.INTEGER);
143.149 + assertNamedParameter(options.getNamedParameters(), NAME_2, DATA_2, Parameter.DEFAULT_TYPE);
143.150 + assertNamedParameter(options.getNamedParameters(), NAME_3, DATA_3, SQLType.BOOLEAN);
143.151 + }
143.152 +
143.153 + private void assertNamedParameter(Collection<NamedParameter> params, String name, Object value, SQLType type) {
143.154 + for (NamedParameter p : params) {
143.155 + if (name.equals(p.getName())) {
143.156 + assertEquals(p.getValue(), value, "value does not match – name: " + name);
143.157 + assertEquals(p.getType(), type, "value does not match – name: " + name);
143.158 + return;
143.159 + }
143.160 + }
143.161 + fail("Named parameter not found: " + name);
143.162 + }
143.163 +
143.164 + @Test
143.165 + public void testParseOptions_PrepareBatch() throws InvalidOptionsException, CLIParserException {
143.166 + String[] args = new String[]{
143.167 + Tokens.BATCH,
143.168 + Tokens.SQL, SQL_1};
143.169 + CLIOptions options = parseOptions(args);
143.170 + options.validate();
143.171 +
143.172 + assertEquals(options.getSql(), SQL_1);
143.173 + assertEquals(options.getMode(), CLIOptions.MODE.PREPARE_BATCH);
143.174 + }
143.175 +
143.176 + @Test
143.177 + public void testParseOptions_ExecuteBatch() throws InvalidOptionsException, CLIParserException {
143.178 + String[] args = new String[]{
143.179 + Tokens.BATCH,
143.180 + Tokens.DB, DATABASE_NAME_1};
143.181 + CLIOptions options = parseOptions(args);
143.182 + options.validate();
143.183 +
143.184 + assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
143.185 + assertEquals(options.getMode(), CLIOptions.MODE.EXECUTE_BATCH);
143.186 + }
143.187 +
143.188 + @Test
143.189 + public void testParseOptions_ShowInfo_Help() throws InvalidOptionsException, CLIParserException {
143.190 + String[] args = new String[]{Tokens.INFO_HELP};
143.191 + CLIOptions options = parseOptions(args);
143.192 + options.validate();
143.193 +
143.194 + assertEquals(options.getMode(), CLIOptions.MODE.JUST_SHOW_INFO);
143.195 + assertEquals(options.getShowInfo().size(), 1);
143.196 + assertTrue(options.getShowInfo().contains(InfoType.HELP));
143.197 + }
143.198 +}
143.199 \ No newline at end of file
144.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
144.2 +++ b/java/sql-dk/src/test/java/info/globalcode/sql/dk/FunctionsTest.java Mon Mar 04 20:15:24 2019 +0100
144.3 @@ -0,0 +1,96 @@
144.4 +/**
144.5 + * SQL-DK
144.6 + * Copyright © 2013 František Kučera (frantovo.cz)
144.7 + *
144.8 + * This program is free software: you can redistribute it and/or modify
144.9 + * it under the terms of the GNU General Public License as published by
144.10 + * the Free Software Foundation, either version 3 of the License, or
144.11 + * (at your option) any later version.
144.12 + *
144.13 + * This program is distributed in the hope that it will be useful,
144.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
144.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
144.16 + * GNU General Public License for more details.
144.17 + *
144.18 + * You should have received a copy of the GNU General Public License
144.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
144.20 + */
144.21 +package info.globalcode.sql.dk;
144.22 +
144.23 +import java.util.ArrayList;
144.24 +import java.util.Collection;
144.25 +import java.util.List;
144.26 +import static org.testng.Assert.*;
144.27 +import org.testng.annotations.*;
144.28 +
144.29 +/**
144.30 + *
144.31 + * @author Ing. František Kučera (frantovo.cz)
144.32 + */
144.33 +public class FunctionsTest {
144.34 +
144.35 + @Test
144.36 + public void testNotNull() {
144.37 + Collection<String> c = null;
144.38 + for (String s : Functions.notNull(c)) {
144.39 + fail("Should not iterate through null collection");
144.40 + }
144.41 +
144.42 + c = new ArrayList<>();
144.43 + c.add("ahoj");
144.44 + int count = 0;
144.45 + for (String s : Functions.notNull(c)) {
144.46 + assertEquals(s, "ahoj", "Wrong item in collection");
144.47 + count++;
144.48 + }
144.49 + assertEquals(count, 1, "Wrong number of iterations");
144.50 + }
144.51 +
144.52 + @Test
144.53 + public void testLpad() {
144.54 + String original = "abc";
144.55 + String padded;
144.56 +
144.57 + padded = Functions.lpad(original, 5);
144.58 + assertEquals(padded, " abc");
144.59 +
144.60 + padded = Functions.lpad(original, 2);
144.61 + assertEquals(padded, original);
144.62 + }
144.63 +
144.64 + @Test
144.65 + public void testRpad() {
144.66 + String original = "abc";
144.67 + String padded;
144.68 +
144.69 + padded = Functions.rpad(original, 5);
144.70 + assertEquals(padded, "abc ");
144.71 +
144.72 + padded = Functions.rpad(original, 2);
144.73 + assertEquals(padded, original);
144.74 + }
144.75 +
144.76 + @Test
144.77 + public void testRepeat() {
144.78 + assertEquals(Functions.repeat('f', 0), "");
144.79 + assertEquals(Functions.repeat('f', 3), "fff");
144.80 + }
144.81 +
144.82 + @Test
144.83 + public void testGetClassHierarchy() {
144.84 + List<Class<? extends HierarchyMockClass2>> hierarchy = Functions.getClassHierarchy(HierarchyMockClass0.class, HierarchyMockClass2.class);
144.85 + assertEquals(hierarchy.size(), 3, "invalid number of classes in the hierarchy");
144.86 + assertEquals(hierarchy.get(0), HierarchyMockClass0.class);
144.87 + assertEquals(hierarchy.get(1), HierarchyMockClass1.class);
144.88 + assertEquals(hierarchy.get(2), HierarchyMockClass2.class);
144.89 + }
144.90 +
144.91 + private static class HierarchyMockClass0 extends HierarchyMockClass1 {
144.92 + }
144.93 +
144.94 + private static class HierarchyMockClass1 extends HierarchyMockClass2 {
144.95 + }
144.96 +
144.97 + private static class HierarchyMockClass2 {
144.98 + }
144.99 +}
145.1 --- a/java/sql-dk/test/info/globalcode/sql/dk/CLIParserTest.java Mon Mar 04 17:06:42 2019 +0100
145.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
145.3 @@ -1,195 +0,0 @@
145.4 -/**
145.5 - * SQL-DK
145.6 - * Copyright © 2013 František Kučera (frantovo.cz)
145.7 - *
145.8 - * This program is free software: you can redistribute it and/or modify
145.9 - * it under the terms of the GNU General Public License as published by
145.10 - * the Free Software Foundation, either version 3 of the License, or
145.11 - * (at your option) any later version.
145.12 - *
145.13 - * This program is distributed in the hope that it will be useful,
145.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
145.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
145.16 - * GNU General Public License for more details.
145.17 - *
145.18 - * You should have received a copy of the GNU General Public License
145.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
145.20 - */
145.21 -package info.globalcode.sql.dk;
145.22 -
145.23 -import info.globalcode.sql.dk.CLIParser.Tokens;
145.24 -import static info.globalcode.sql.dk.CLIParser.TYPE_NAME_SEPARATOR;
145.25 -import info.globalcode.sql.dk.InfoLister.InfoType;
145.26 -import java.io.ByteArrayInputStream;
145.27 -import java.util.Collection;
145.28 -import static org.testng.Assert.*;
145.29 -import org.testng.annotations.BeforeMethod;
145.30 -import org.testng.annotations.Test;
145.31 -
145.32 -/**
145.33 - *
145.34 - * @author Ing. František Kučera (frantovo.cz)
145.35 - */
145.36 -public class CLIParserTest {
145.37 -
145.38 - private static final String DATABASE_NAME_1 = "some database 1";
145.39 - private static final String SQL_1 = "SELECT * FROM table1";
145.40 - private static final String DATA_1 = "aaa";
145.41 - private static final String DATA_2 = "bbb";
145.42 - private static final String DATA_3 = "ccc";
145.43 - private static final String NAME_1 = "param1";
145.44 - private static final String NAME_2 = "param2";
145.45 - private static final String NAME_3 = "param3";
145.46 - private CLIParser parser;
145.47 -
145.48 - @BeforeMethod
145.49 - public void setUpMethod() throws Exception {
145.50 - parser = new CLIParser();
145.51 - }
145.52 -
145.53 - private CLIOptions parseOptions(String[] args) throws CLIParserException {
145.54 - return parser.parseOptions(args, new ByteArrayInputStream("".getBytes()));
145.55 - }
145.56 -
145.57 - @Test
145.58 - public void testParseOptions_QueryNow_NoParams() throws InvalidOptionsException, CLIParserException {
145.59 - String[] args = new String[]{
145.60 - Tokens.DB, DATABASE_NAME_1,
145.61 - Tokens.SQL, SQL_1};
145.62 - CLIOptions options = parseOptions(args);
145.63 - options.validate();
145.64 -
145.65 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.66 - assertEquals(options.getSql(), SQL_1);
145.67 - assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
145.68 - assertTrue(options.getNamedParameters().isEmpty(), "Named parameters should be empty.");
145.69 - assertTrue(options.getNumberedParameters().isEmpty(), "Numbered parameters should be empty.");
145.70 - }
145.71 -
145.72 - @Test
145.73 - public void testParseOptions_QueryNow_Numbered() throws InvalidOptionsException, CLIParserException {
145.74 - String[] args = new String[]{
145.75 - Tokens.DB, DATABASE_NAME_1,
145.76 - Tokens.SQL, SQL_1,
145.77 - Tokens.DATA, DATA_1, DATA_2, DATA_3};
145.78 - CLIOptions options = parseOptions(args);
145.79 - options.validate();
145.80 -
145.81 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.82 - assertEquals(options.getSql(), SQL_1);
145.83 - assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
145.84 - assertEquals(options.getNumberedParameters().size(), 3);
145.85 - assertEquals(options.getNumberedParameters().get(0).getValue(), DATA_1);
145.86 - assertEquals(options.getNumberedParameters().get(1).getValue(), DATA_2);
145.87 - assertEquals(options.getNumberedParameters().get(2).getValue(), DATA_3);
145.88 - assertEquals(options.getNumberedParameters().get(0).getType(), Parameter.DEFAULT_TYPE);
145.89 - assertEquals(options.getNumberedParameters().get(1).getType(), Parameter.DEFAULT_TYPE);
145.90 - assertEquals(options.getNumberedParameters().get(2).getType(), Parameter.DEFAULT_TYPE);
145.91 - }
145.92 -
145.93 - @Test
145.94 - public void testParseOptions_QueryNow_Numbered_withTypes() throws InvalidOptionsException, CLIParserException {
145.95 - String[] args = new String[]{
145.96 - Tokens.DB, DATABASE_NAME_1,
145.97 - Tokens.SQL, SQL_1,
145.98 - Tokens.TYPES, " INTEGER,VARCHAR, BOOLEAN",
145.99 - Tokens.DATA, DATA_1, DATA_2, DATA_3};
145.100 - CLIOptions options = parseOptions(args);
145.101 - options.validate();
145.102 -
145.103 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.104 - assertEquals(options.getSql(), SQL_1);
145.105 - assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
145.106 - assertEquals(options.getNumberedParameters().size(), 3);
145.107 - assertEquals(options.getNumberedParameters().get(0).getValue(), DATA_1);
145.108 - assertEquals(options.getNumberedParameters().get(1).getValue(), DATA_2);
145.109 - assertEquals(options.getNumberedParameters().get(2).getValue(), DATA_3);
145.110 - assertEquals(options.getNumberedParameters().get(0).getType(), SQLType.INTEGER);
145.111 - assertEquals(options.getNumberedParameters().get(1).getType(), SQLType.VARCHAR);
145.112 - assertEquals(options.getNumberedParameters().get(2).getType(), SQLType.BOOLEAN);
145.113 - }
145.114 -
145.115 - @Test
145.116 - public void testParseOptions_QueryNow_Named() throws InvalidOptionsException, CLIParserException {
145.117 - String[] args = new String[]{
145.118 - Tokens.DB, DATABASE_NAME_1,
145.119 - Tokens.SQL, SQL_1,
145.120 - Tokens.DATA_NAMED, NAME_1, DATA_1, NAME_2, DATA_2, NAME_3, DATA_3};
145.121 - CLIOptions options = parseOptions(args);
145.122 - options.validate();
145.123 -
145.124 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.125 - assertEquals(options.getSql(), SQL_1);
145.126 - assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
145.127 - assertEquals(options.getNamedParameters().size(), 3);
145.128 - assertNamedParameter(options.getNamedParameters(), NAME_1, DATA_1, Parameter.DEFAULT_TYPE);
145.129 - assertNamedParameter(options.getNamedParameters(), NAME_2, DATA_2, Parameter.DEFAULT_TYPE);
145.130 - assertNamedParameter(options.getNamedParameters(), NAME_3, DATA_3, Parameter.DEFAULT_TYPE);
145.131 - }
145.132 -
145.133 - @Test
145.134 - public void testParseOptions_QueryNow_Named_withTypes() throws InvalidOptionsException, CLIParserException {
145.135 - String[] args = new String[]{
145.136 - Tokens.DB, DATABASE_NAME_1,
145.137 - Tokens.SQL, SQL_1,
145.138 - Tokens.NAME_PREFIX, "$",
145.139 - Tokens.TYPES, " " + NAME_1 + TYPE_NAME_SEPARATOR + "INTEGER" + "," + NAME_3 + TYPE_NAME_SEPARATOR + "BOOLEAN",
145.140 - Tokens.DATA_NAMED, NAME_1, DATA_1, NAME_2, DATA_2, NAME_3, DATA_3};
145.141 - CLIOptions options = parseOptions(args);
145.142 - options.validate();
145.143 -
145.144 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.145 - assertEquals(options.getSql(), SQL_1);
145.146 - assertEquals(options.getMode(), CLIOptions.MODE.QUERY_NOW);
145.147 - assertEquals(options.getNamedParameters().size(), 3);
145.148 - assertNamedParameter(options.getNamedParameters(), NAME_1, DATA_1, SQLType.INTEGER);
145.149 - assertNamedParameter(options.getNamedParameters(), NAME_2, DATA_2, Parameter.DEFAULT_TYPE);
145.150 - assertNamedParameter(options.getNamedParameters(), NAME_3, DATA_3, SQLType.BOOLEAN);
145.151 - }
145.152 -
145.153 - private void assertNamedParameter(Collection<NamedParameter> params, String name, Object value, SQLType type) {
145.154 - for (NamedParameter p : params) {
145.155 - if (name.equals(p.getName())) {
145.156 - assertEquals(p.getValue(), value, "value does not match – name: " + name);
145.157 - assertEquals(p.getType(), type, "value does not match – name: " + name);
145.158 - return;
145.159 - }
145.160 - }
145.161 - fail("Named parameter not found: " + name);
145.162 - }
145.163 -
145.164 - @Test
145.165 - public void testParseOptions_PrepareBatch() throws InvalidOptionsException, CLIParserException {
145.166 - String[] args = new String[]{
145.167 - Tokens.BATCH,
145.168 - Tokens.SQL, SQL_1};
145.169 - CLIOptions options = parseOptions(args);
145.170 - options.validate();
145.171 -
145.172 - assertEquals(options.getSql(), SQL_1);
145.173 - assertEquals(options.getMode(), CLIOptions.MODE.PREPARE_BATCH);
145.174 - }
145.175 -
145.176 - @Test
145.177 - public void testParseOptions_ExecuteBatch() throws InvalidOptionsException, CLIParserException {
145.178 - String[] args = new String[]{
145.179 - Tokens.BATCH,
145.180 - Tokens.DB, DATABASE_NAME_1};
145.181 - CLIOptions options = parseOptions(args);
145.182 - options.validate();
145.183 -
145.184 - assertEquals(options.getDatabaseName(), DATABASE_NAME_1);
145.185 - assertEquals(options.getMode(), CLIOptions.MODE.EXECUTE_BATCH);
145.186 - }
145.187 -
145.188 - @Test
145.189 - public void testParseOptions_ShowInfo_Help() throws InvalidOptionsException, CLIParserException {
145.190 - String[] args = new String[]{Tokens.INFO_HELP};
145.191 - CLIOptions options = parseOptions(args);
145.192 - options.validate();
145.193 -
145.194 - assertEquals(options.getMode(), CLIOptions.MODE.JUST_SHOW_INFO);
145.195 - assertEquals(options.getShowInfo().size(), 1);
145.196 - assertTrue(options.getShowInfo().contains(InfoType.HELP));
145.197 - }
145.198 -}
145.199 \ No newline at end of file
146.1 --- a/java/sql-dk/test/info/globalcode/sql/dk/FunctionsTest.java Mon Mar 04 17:06:42 2019 +0100
146.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
146.3 @@ -1,96 +0,0 @@
146.4 -/**
146.5 - * SQL-DK
146.6 - * Copyright © 2013 František Kučera (frantovo.cz)
146.7 - *
146.8 - * This program is free software: you can redistribute it and/or modify
146.9 - * it under the terms of the GNU General Public License as published by
146.10 - * the Free Software Foundation, either version 3 of the License, or
146.11 - * (at your option) any later version.
146.12 - *
146.13 - * This program is distributed in the hope that it will be useful,
146.14 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
146.15 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
146.16 - * GNU General Public License for more details.
146.17 - *
146.18 - * You should have received a copy of the GNU General Public License
146.19 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
146.20 - */
146.21 -package info.globalcode.sql.dk;
146.22 -
146.23 -import java.util.ArrayList;
146.24 -import java.util.Collection;
146.25 -import java.util.List;
146.26 -import static org.testng.Assert.*;
146.27 -import org.testng.annotations.*;
146.28 -
146.29 -/**
146.30 - *
146.31 - * @author Ing. František Kučera (frantovo.cz)
146.32 - */
146.33 -public class FunctionsTest {
146.34 -
146.35 - @Test
146.36 - public void testNotNull() {
146.37 - Collection<String> c = null;
146.38 - for (String s : Functions.notNull(c)) {
146.39 - fail("Should not iterate through null collection");
146.40 - }
146.41 -
146.42 - c = new ArrayList<>();
146.43 - c.add("ahoj");
146.44 - int count = 0;
146.45 - for (String s : Functions.notNull(c)) {
146.46 - assertEquals(s, "ahoj", "Wrong item in collection");
146.47 - count++;
146.48 - }
146.49 - assertEquals(count, 1, "Wrong number of iterations");
146.50 - }
146.51 -
146.52 - @Test
146.53 - public void testLpad() {
146.54 - String original = "abc";
146.55 - String padded;
146.56 -
146.57 - padded = Functions.lpad(original, 5);
146.58 - assertEquals(padded, " abc");
146.59 -
146.60 - padded = Functions.lpad(original, 2);
146.61 - assertEquals(padded, original);
146.62 - }
146.63 -
146.64 - @Test
146.65 - public void testRpad() {
146.66 - String original = "abc";
146.67 - String padded;
146.68 -
146.69 - padded = Functions.rpad(original, 5);
146.70 - assertEquals(padded, "abc ");
146.71 -
146.72 - padded = Functions.rpad(original, 2);
146.73 - assertEquals(padded, original);
146.74 - }
146.75 -
146.76 - @Test
146.77 - public void testRepeat() {
146.78 - assertEquals(Functions.repeat('f', 0), "");
146.79 - assertEquals(Functions.repeat('f', 3), "fff");
146.80 - }
146.81 -
146.82 - @Test
146.83 - public void testGetClassHierarchy() {
146.84 - List<Class<? extends HierarchyMockClass2>> hierarchy = Functions.getClassHierarchy(HierarchyMockClass0.class, HierarchyMockClass2.class);
146.85 - assertEquals(hierarchy.size(), 3, "invalid number of classes in the hierarchy");
146.86 - assertEquals(hierarchy.get(0), HierarchyMockClass0.class);
146.87 - assertEquals(hierarchy.get(1), HierarchyMockClass1.class);
146.88 - assertEquals(hierarchy.get(2), HierarchyMockClass2.class);
146.89 - }
146.90 -
146.91 - private static class HierarchyMockClass0 extends HierarchyMockClass1 {
146.92 - }
146.93 -
146.94 - private static class HierarchyMockClass1 extends HierarchyMockClass2 {
146.95 - }
146.96 -
146.97 - private static class HierarchyMockClass2 {
146.98 - }
146.99 -}