java/sql-dk/src/main/java/info/globalcode/sql/dk/CLIOptions.java
author František Kučera <franta-hg@frantovo.cz>
Tue, 05 Mar 2019 22:03:02 +0100
branchv_0
changeset 246 277c18b48762
parent 238 4a1864c3e867
child 250 aae5009bd0af
permissions -rw-r--r--
support custom relation names in the XML formatter (added --relation CLI option)

/**
 * SQL-DK
 * Copyright © 2013 František Kučera (frantovo.cz)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package info.globalcode.sql.dk;

import static info.globalcode.sql.dk.Functions.isNotEmpty;
import static info.globalcode.sql.dk.Functions.equalz;
import info.globalcode.sql.dk.InfoLister.InfoType;
import info.globalcode.sql.dk.configuration.Properties;
import info.globalcode.sql.dk.configuration.Property;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * Holds options from command line, validates them, combines with configuration and provides derived
 * objects.
 *
 * @author Ing. František Kučera (frantovo.cz)
 */
public class CLIOptions {

	public static final String DEFAULT_NAME_PREFIX = ":";
	public static final String DEFAULT_NAME_SUFFIX = "(?=([^\\w]|$))";
	private String sql;
	private String databaseName;
	private final List<String> relationNames = new ArrayList<>();
	private final Set<String> databaseNamesToTest = new LinkedHashSet<>();
	private final Set<String> databaseNamesToListProperties = new LinkedHashSet<>();
	private final Set<String> formatterNamesToListProperties = new LinkedHashSet<>();
	private String namePrefix = DEFAULT_NAME_PREFIX;
	private String nameSuffix = DEFAULT_NAME_SUFFIX;
	private String formatterName;
	private boolean batch;
	private final Properties formatterProperties = new Properties();
	private final Properties databaseProperties = new Properties();

	public enum MODE {

		QUERY_NOW,
		PREPARE_BATCH,
		EXECUTE_BATCH,
		JUST_SHOW_INFO
	}
	private final List<NamedParameter> namedParameters = new ArrayList<>();
	private final List<Parameter> numberedParameters = new ArrayList<>();
	private final EnumSet<InfoType> showInfo = EnumSet.noneOf(InfoType.class);

	public void validate() throws InvalidOptionsException {
		InvalidOptionsException e = new InvalidOptionsException();

		MODE mode = getMode();
		if (mode == null) {
			e.addProblem(new InvalidOptionsException.OptionProblem("Invalid combination of DB, SQL and BATCH – please specify just 2 of this 3 options"));
		} else if (mode == MODE.JUST_SHOW_INFO) {
			if (!namedParameters.isEmpty()) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not use named parameters if just showing info."));
			}
			if (!numberedParameters.isEmpty()) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not use numbered parameters if just showing info."));
			}
			if (isNotEmpty(sql, false)) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify SQL if just showing info."));
			}
			if (isNotEmpty(databaseName, false)) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify database if just showing info."));
			}
			if (batch) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify batch if just showing info."));
			}
			if (!equalz(namePrefix, DEFAULT_NAME_PREFIX)) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name prefix if just showing info."));
			}
			if (!equalz(nameSuffix, DEFAULT_NAME_SUFFIX)) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Do not specify name suffix if just showing info."));
			}
			if (showInfo.contains(InfoType.CONNECTION) && databaseNamesToTest.isEmpty()) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Please specify which database should be tested."));
			}
			if (showInfo.contains(InfoType.JDBC_PROPERTIES) && databaseNamesToListProperties.isEmpty()) {
				e.addProblem(new InvalidOptionsException.OptionProblem("Please specify for which database the properties should be listed."));
			}
		}

		if (!namedParameters.isEmpty() && !numberedParameters.isEmpty()) {
			e.addProblem(new InvalidOptionsException.OptionProblem("Named and numbered parameters can not be used together in one command."));
		}

		try {
			Pattern.compile(namePrefix + "test" + nameSuffix);
		} catch (PatternSyntaxException regexException) {
			e.addProblem(new InvalidOptionsException.OptionProblem("Ivalid regular expression in name prefix or suffix", regexException));
		}

		if (e.hasProblems()) {
			throw e;
		}
	}

	private boolean hasSql() {
		return isNotEmpty(getSql(), true);
	}

	private boolean hasDb() {
		return isNotEmpty(getDatabaseName(), true);
	}

	/**
	 * Depends on options: DB, BATCH, SQL
	 *
	 * @return mode | or null if options are not yet initialized or combination of options is
	 * invalid
	 */
	public MODE getMode() {
		if (hasDb() && !batch && hasSql()) {
			return MODE.QUERY_NOW;
		} else if (!hasDb() && batch && hasSql()) {
			return MODE.PREPARE_BATCH;
		} else if (hasDb() && batch && !hasSql()) {
			return MODE.EXECUTE_BATCH;
		} else {
			return showInfo.isEmpty() ? null : MODE.JUST_SHOW_INFO;
		}
	}

	public String getSql() {
		return sql;
	}

	public void setSql(String sql) {
		this.sql = sql;
	}

	public String getDatabaseName() {
		return databaseName;
	}

	public void setDatabaseName(String databaseName) {
		this.databaseName = databaseName;
	}

	public List<String> getRelationNames() {
		return relationNames;
	}

	public void addRelationName(String name) {
		relationNames.add(name);
	}

	public void setBatch(boolean batch) {
		this.batch = batch;
	}

	public Collection<NamedParameter> getNamedParameters() {
		return namedParameters;
	}

	public List<Parameter> getNumberedParameters() {
		return numberedParameters;
	}

	public void addNumberedParameter(Parameter p) {
		numberedParameters.add(p);
	}

	public void addNamedParameter(NamedParameter p) {
		namedParameters.add(p);
	}

	public Properties getDatabaseProperties() {
		return databaseProperties;
	}

	public Properties getFormatterProperties() {
		return formatterProperties;
	}

	public void addDatabaseProperty(Property p) {
		databaseProperties.add(p);
	}

	public void addFormatterProperty(Property p) {
		formatterProperties.add(p);
	}

	/**
	 * @return regular expression describing the name prefix
	 */
	public String getNamePrefix() {
		return namePrefix;
	}

	/**
	 * @param namePrefix
	 * @see #getNamePrefix()
	 */
	public void setNamePrefix(String namePrefix) {
		this.namePrefix = namePrefix;
	}

	/**
	 * @return regular expression describing the name prefix
	 */
	public String getNameSuffix() {
		return nameSuffix;
	}

	/**
	 * @param nameSuffix
	 * @see #getNameSuffix()
	 */
	public void setNameSuffix(String nameSuffix) {
		this.nameSuffix = nameSuffix;
	}

	public String getFormatterName() {
		return formatterName;
	}

	public void setFormatterName(String formatterName) {
		this.formatterName = formatterName;
	}

	public void addShowInfo(InfoType info) {
		showInfo.add(info);
	}

	public EnumSet<InfoType> getShowInfo() {
		return showInfo;
	}

	public Set<String> getDatabaseNamesToTest() {
		return databaseNamesToTest;
	}

	public void addDatabaseNameToTest(String name) {
		databaseNamesToTest.add(name);
	}

	public Set<String> getDatabaseNamesToListProperties() {
		return databaseNamesToListProperties;
	}

	public void addDatabaseNameToListProperties(String name) {
		databaseNamesToListProperties.add(name);
	}

	public Set<String> getFormatterNamesToListProperties() {
		return formatterNamesToListProperties;
	}

	public void addFormatterNameToListProperties(String name) {
		formatterNamesToListProperties.add(name);
	}

	public SQLCommand getSQLCommand() {
		if (namedParameters.isEmpty()) {
			return new SQLCommandNumbered(sql, numberedParameters);
		} else {
			return new SQLCommandNamed(sql, namedParameters, namePrefix, nameSuffix);
		}
	}

	public OutputStream getOutputStream() {
		return System.out;
	}

	public InputStream getInputStream() {
		return System.in;
	}
}