1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIOptions.java Mon Mar 04 20:15:24 2019 +0100
1.3 @@ -0,0 +1,283 @@
1.4 +/**
1.5 + * SQL-DK
1.6 + * Copyright © 2013 František Kučera (frantovo.cz)
1.7 + *
1.8 + * This program is free software: you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation, either version 3 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License
1.19 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.20 + */
1.21 +package info.globalcode.sql.dk;
1.22 +
1.23 +import static info.globalcode.sql.dk.Functions.isNotEmpty;
1.24 +import static info.globalcode.sql.dk.Functions.equalz;
1.25 +import info.globalcode.sql.dk.InfoLister.InfoType;
1.26 +import info.globalcode.sql.dk.configuration.Properties;
1.27 +import info.globalcode.sql.dk.configuration.Property;
1.28 +import java.io.InputStream;
1.29 +import java.io.OutputStream;
1.30 +import java.util.ArrayList;
1.31 +import java.util.Collection;
1.32 +import java.util.EnumSet;
1.33 +import java.util.LinkedHashSet;
1.34 +import java.util.List;
1.35 +import java.util.Set;
1.36 +import java.util.regex.Pattern;
1.37 +import java.util.regex.PatternSyntaxException;
1.38 +
1.39 +/**
1.40 + * Holds options from command line, validates them, combines with configuration and provides derived
1.41 + * objects.
1.42 + *
1.43 + * @author Ing. František Kučera (frantovo.cz)
1.44 + */
1.45 +public class CLIOptions {
1.46 +
1.47 + public static final String DEFAULT_NAME_PREFIX = ":";
1.48 + public static final String DEFAULT_NAME_SUFFIX = "(?=([^\\w]|$))";
1.49 + private String sql;
1.50 + private String databaseName;
1.51 + private final Set<String> databaseNamesToTest = new LinkedHashSet<>();
1.52 + private final Set<String> databaseNamesToListProperties = new LinkedHashSet<>();
1.53 + private final Set<String> formatterNamesToListProperties = new LinkedHashSet<>();
1.54 + private String namePrefix = DEFAULT_NAME_PREFIX;
1.55 + private String nameSuffix = DEFAULT_NAME_SUFFIX;
1.56 + private String formatterName;
1.57 + private boolean batch;
1.58 + private final Properties formatterProperties = new Properties();
1.59 + private final Properties databaseProperties = new Properties();
1.60 +
1.61 + public enum MODE {
1.62 +
1.63 + QUERY_NOW,
1.64 + PREPARE_BATCH,
1.65 + EXECUTE_BATCH,
1.66 + JUST_SHOW_INFO
1.67 + }
1.68 + private final List<NamedParameter> namedParameters = new ArrayList<>();
1.69 + private final List<Parameter> numberedParameters = new ArrayList<>();
1.70 + private final EnumSet<InfoType> showInfo = EnumSet.noneOf(InfoType.class);
1.71 +
1.72 + public void validate() throws InvalidOptionsException {
1.73 + InvalidOptionsException e = new InvalidOptionsException();
1.74 +
1.75 + MODE mode = getMode();
1.76 + if (mode == null) {
1.77 + e.addProblem(new InvalidOptionsException.OptionProblem("Invalid combination of DB, SQL and BATCH – please specify just 2 of this 3 options"));
1.78 + } else if (mode == MODE.JUST_SHOW_INFO) {
1.79 + if (!namedParameters.isEmpty()) {
1.80 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not use named parameters if just showing info."));
1.81 + }
1.82 + if (!numberedParameters.isEmpty()) {
1.83 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not use numbered parameters if just showing info."));
1.84 + }
1.85 + if (isNotEmpty(sql, false)) {
1.86 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify SQL if just showing info."));
1.87 + }
1.88 + if (isNotEmpty(databaseName, false)) {
1.89 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify database if just showing info."));
1.90 + }
1.91 + if (batch) {
1.92 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify batch if just showing info."));
1.93 + }
1.94 + if (!equalz(namePrefix, DEFAULT_NAME_PREFIX)) {
1.95 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name prefix if just showing info."));
1.96 + }
1.97 + if (!equalz(nameSuffix, DEFAULT_NAME_SUFFIX)) {
1.98 + e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name suffix if just showing info."));
1.99 + }
1.100 + if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) {
1.101 + e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested."));
1.102 + }
1.103 + if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) {
1.104 + e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed."));
1.105 + }
1.106 + }
1.107 +
1.108 + if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) {
1.109 + e.addProblem(new InvalidOptionsException.OptionProblem("Named and numbered parameters can not be used together in one command."));
1.110 + }
1.111 +
1.112 + try {
1.113 + Pattern.compile(namePrefix + "test" + nameSuffix);
1.114 + } catch (PatternSyntaxException regexException) {
1.115 + e.addProblem(new InvalidOptionsException.OptionProblem("Ivalid regular expression in name prefix or suffix", regexException));
1.116 + }
1.117 +
1.118 + if (e.hasProblems()) {
1.119 + throw e;
1.120 + }
1.121 + }
1.122 +
1.123 + private boolean hasSql() {
1.124 + return isNotEmpty(getSql(), true);
1.125 + }
1.126 +
1.127 + private boolean hasDb() {
1.128 + return isNotEmpty(getDatabaseName(), true);
1.129 + }
1.130 +
1.131 + /**
1.132 + * Depends on options: DB, BATCH, SQL
1.133 + *
1.134 + * @return mode | or null if options are not yet initialized or combination of options is
1.135 + * invalid
1.136 + */
1.137 + public MODE getMode() {
1.138 + if (hasDb() && !batch && hasSql()) {
1.139 + return MODE.QUERY_NOW;
1.140 + } else if (!hasDb() && batch && hasSql()) {
1.141 + return MODE.PREPARE_BATCH;
1.142 + } else if (hasDb() && batch && !hasSql()) {
1.143 + return MODE.EXECUTE_BATCH;
1.144 + } else {
1.145 + return showInfo.isEmpty() ? null : MODE.JUST_SHOW_INFO;
1.146 + }
1.147 + }
1.148 +
1.149 + public String getSql() {
1.150 + return sql;
1.151 + }
1.152 +
1.153 + public void setSql(String sql) {
1.154 + this.sql = sql;
1.155 + }
1.156 +
1.157 + public String getDatabaseName() {
1.158 + return databaseName;
1.159 + }
1.160 +
1.161 + public void setDatabaseName(String databaseName) {
1.162 + this.databaseName = databaseName;
1.163 + }
1.164 +
1.165 + public void setBatch(boolean batch) {
1.166 + this.batch = batch;
1.167 + }
1.168 +
1.169 + public Collection<NamedParameter> getNamedParameters() {
1.170 + return namedParameters;
1.171 + }
1.172 +
1.173 + public List<Parameter> getNumberedParameters() {
1.174 + return numberedParameters;
1.175 + }
1.176 +
1.177 + public void addNumberedParameter(Parameter p) {
1.178 + numberedParameters.add(p);
1.179 + }
1.180 +
1.181 + public void addNamedParameter(NamedParameter p) {
1.182 + namedParameters.add(p);
1.183 + }
1.184 +
1.185 + public Properties getDatabaseProperties() {
1.186 + return databaseProperties;
1.187 + }
1.188 +
1.189 + public Properties getFormatterProperties() {
1.190 + return formatterProperties;
1.191 + }
1.192 +
1.193 + public void addDatabaseProperty(Property p) {
1.194 + databaseProperties.add(p);
1.195 + }
1.196 +
1.197 + public void addFormatterProperty(Property p) {
1.198 + formatterProperties.add(p);
1.199 + }
1.200 +
1.201 + /**
1.202 + * @return regular expression describing the name prefix
1.203 + */
1.204 + public String getNamePrefix() {
1.205 + return namePrefix;
1.206 + }
1.207 +
1.208 + /**
1.209 + * @param namePrefix
1.210 + * @see #getNamePrefix()
1.211 + */
1.212 + public void setNamePrefix(String namePrefix) {
1.213 + this.namePrefix = namePrefix;
1.214 + }
1.215 +
1.216 + /**
1.217 + * @return regular expression describing the name prefix
1.218 + */
1.219 + public String getNameSuffix() {
1.220 + return nameSuffix;
1.221 + }
1.222 +
1.223 + /**
1.224 + * @param nameSuffix
1.225 + * @see #getNameSuffix()
1.226 + */
1.227 + public void setNameSuffix(String nameSuffix) {
1.228 + this.nameSuffix = nameSuffix;
1.229 + }
1.230 +
1.231 + public String getFormatterName() {
1.232 + return formatterName;
1.233 + }
1.234 +
1.235 + public void setFormatterName(String formatterName) {
1.236 + this.formatterName = formatterName;
1.237 + }
1.238 +
1.239 + public void addShowInfo(InfoType info) {
1.240 + showInfo.add(info);
1.241 + }
1.242 +
1.243 + public EnumSet<InfoType> getShowInfo() {
1.244 + return showInfo;
1.245 + }
1.246 +
1.247 + public Set<String> getDatabaseNamesToTest() {
1.248 + return databaseNamesToTest;
1.249 + }
1.250 +
1.251 + public void addDatabaseNameToTest(String name) {
1.252 + databaseNamesToTest.add(name);
1.253 + }
1.254 +
1.255 + public Set<String> getDatabaseNamesToListProperties() {
1.256 + return databaseNamesToListProperties;
1.257 + }
1.258 +
1.259 + public void addDatabaseNameToListProperties(String name) {
1.260 + databaseNamesToListProperties.add(name);
1.261 + }
1.262 +
1.263 + public Set<String> getFormatterNamesToListProperties() {
1.264 + return formatterNamesToListProperties;
1.265 + }
1.266 +
1.267 + public void addFormatterNameToListProperties(String name) {
1.268 + formatterNamesToListProperties.add(name);
1.269 + }
1.270 +
1.271 + public SQLCommand getSQLCommand() {
1.272 + if (namedParameters.isEmpty()) {
1.273 + return new SQLCommandNumbered(sql, numberedParameters);
1.274 + } else {
1.275 + return new SQLCommandNamed(sql, namedParameters, namePrefix, nameSuffix);
1.276 + }
1.277 + }
1.278 +
1.279 + public OutputStream getOutputStream() {
1.280 + return System.out;
1.281 + }
1.282 +
1.283 + public InputStream getInputStream() {
1.284 + return System.in;
1.285 + }
1.286 +}