diff -r 7e08730da258 -r 4a1864c3e867 java/sql-dk/src/info/globalcode/sql/dk/CLIStarter.java --- a/java/sql-dk/src/info/globalcode/sql/dk/CLIStarter.java Mon Mar 04 17:06:42 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/** - * 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 . - */ -package info.globalcode.sql.dk; - -import info.globalcode.sql.dk.configuration.ConfigurationProvider; -import info.globalcode.sql.dk.CLIOptions.MODE; -import info.globalcode.sql.dk.batch.Batch; -import info.globalcode.sql.dk.batch.BatchDecoder; -import info.globalcode.sql.dk.batch.BatchException; -import info.globalcode.sql.dk.batch.BatchEncoder; -import info.globalcode.sql.dk.configuration.Configuration; -import info.globalcode.sql.dk.configuration.ConfigurationException; -import info.globalcode.sql.dk.configuration.DatabaseDefinition; -import info.globalcode.sql.dk.configuration.FormatterDefinition; -import info.globalcode.sql.dk.configuration.Loader; -import info.globalcode.sql.dk.configuration.NameIdentified; -import info.globalcode.sql.dk.configuration.PropertyDeclaration; -import info.globalcode.sql.dk.formatting.Formatter; -import info.globalcode.sql.dk.formatting.FormatterContext; -import info.globalcode.sql.dk.formatting.FormatterException; -import info.globalcode.sql.dk.jmx.ConnectionManagement; -import info.globalcode.sql.dk.jmx.ManagementUtils; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.sql.SQLException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -/** - * Entry point of the command line interface of SQL-DK. - * - * @author Ing. František Kučera (frantovo.cz) - */ -public class CLIStarter implements ConfigurationProvider { - - // help:exit-codes - public static final int EXIT_SUCCESS = 0; // doc:success - public static final int EXIT_UNEXPECTED_ERROR = 1; // doc:unexpected error (probably bug) - // 2 is reserved: http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF - public static final int EXIT_SQL_ERROR = 3; // doc:SQL error - public static final int EXIT_CLI_PARSE_ERROR = 4; // doc:CLI options parse error - public static final int EXIT_CLI_VALIDATE_ERROR = 5; // doc:CLI options validation error - public static final int EXIT_CONFIGURATION_ERROR = 6; // doc:configuration error - public static final int EXIT_FORMATTING_ERROR = 7; // doc:formatting error - public static final int EXIT_BATCH_ERROR = 8; // doc:batch error - private static final Logger log = Logger.getLogger(CLIStarter.class.getName()); - private final CLIOptions options; - private final Loader configurationLoader = new Loader(); - private Configuration configuration; - - public static void main(String[] args) { - log.log(Level.FINE, "Starting " + Constants.PROGRAM_NAME); - int exitCode; - - if (args.length == 0) { - args = new String[]{CLIParser.Tokens.INFO_HELP}; - } - - try { - CLIParser parser = new CLIParser(); - CLIOptions options = parser.parseOptions(args, System.in); - options.validate(); - CLIStarter starter = new CLIStarter(options); - starter.installDefaultConfiguration(); - starter.process(); - log.log(Level.FINE, "All done"); - exitCode = EXIT_SUCCESS; - } catch (CLIParserException e) { - log.log(Level.SEVERE, "Unable to parse CLI options", e); - exitCode = EXIT_CLI_PARSE_ERROR; - } catch (InvalidOptionsException e) { - log.log(Level.SEVERE, "Invalid CLI options", e); - for (InvalidOptionsException.OptionProblem p : e.getProblems()) { - LogRecord r = new LogRecord(Level.SEVERE, "Option problem: {0}"); - r.setThrown(p.getException()); - r.setParameters(new Object[]{p.getDescription()}); - log.log(r); - } - exitCode = EXIT_CLI_VALIDATE_ERROR; - } catch (ConfigurationException e) { - log.log(Level.SEVERE, "Configuration problem", e); - exitCode = EXIT_CONFIGURATION_ERROR; - } catch (SQLException e) { - log.log(Level.SEVERE, "SQL problem", e); - exitCode = EXIT_SQL_ERROR; - } catch (FormatterException e) { - log.log(Level.SEVERE, "Formatting problem", e); - exitCode = EXIT_FORMATTING_ERROR; - } catch (BatchException e) { - log.log(Level.SEVERE, "Batch problem", e); - exitCode = EXIT_BATCH_ERROR; - } - - System.exit(exitCode); - } - - public CLIStarter(CLIOptions options) { - this.options = options; - } - - private void process() throws ConfigurationException, SQLException, FormatterException, BatchException { - MODE mode = options.getMode(); - - /** Show info */ - if (!options.getShowInfo().isEmpty()) { - PrintStream infoOut = mode == MODE.JUST_SHOW_INFO ? System.out : System.err; - InfoLister infoLister = new InfoLister(infoOut, this, options); - infoLister.showInfo(); - } - - switch (mode) { - case QUERY_NOW: - processQueryNow(); - break; - case PREPARE_BATCH: - processPrepareBatch(); - break; - case EXECUTE_BATCH: - processExecuteBatch(); - break; - case JUST_SHOW_INFO: - // already done above - break; - default: - log.log(Level.SEVERE, "Unsupported mode: {0}", mode); - break; - } - - generateBashCompletion(); - } - - private void processQueryNow() throws ConfigurationException, SQLException, FormatterException { - DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName()); - FormatterDefinition fd = configuration.getFormatter(options.getFormatterName()); - ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName()); - - try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) { - log.log(Level.FINE, "Database connected"); - try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) { - c.executeQuery(options.getSQLCommand(), f); - } - } - } - - private void processPrepareBatch() throws BatchException { - BatchEncoder enc = new BatchEncoder(); - int length = enc.encode(options.getSQLCommand(), options.getOutputStream()); - log.log(Level.FINE, "Prepared batch size: {0} bytes", length); - } - - private void processExecuteBatch() throws ConfigurationException, SQLException, FormatterException, BatchException { - BatchDecoder dec = new BatchDecoder(); - Batch b = dec.decode(options.getInputStream()); - - DatabaseDefinition dd = getConfiguration().getDatabase(options.getDatabaseName()); - FormatterDefinition fd = configuration.getFormatter(options.getFormatterName()); - ConnectionManagement jmxBean = ManagementUtils.registerMBean(dd.getName()); - - try (DatabaseConnection c = dd.connect(options.getDatabaseProperties(), jmxBean)) { - log.log(Level.FINE, "Database connected"); - try (Formatter f = fd.getInstance(new FormatterContext(options.getOutputStream(), options.getFormatterProperties()))) { - c.executeBatch(b, f); - } - } - } - - @Override - public Configuration getConfiguration() throws ConfigurationException { - if (configuration == null) { - configuration = configurationLoader.loadConfiguration(); - } - return configuration; - } - - private void installDefaultConfiguration() throws ConfigurationException { - Constants.DIR.mkdir(); - - if (Constants.CONFIG_FILE.exists()) { - log.log(Level.FINER, "Config file already exists: {0}", Constants.CONFIG_FILE); - } else { - try { - Functions.installResource(Constants.EXAMPLE_CONFIG_FILE, Constants.CONFIG_FILE); - log.log(Level.FINE, "Installing default config file: {0}", Constants.CONFIG_FILE); - } catch (IOException e) { - throw new ConfigurationException("Unable to write example configuration to " + Constants.CONFIG_FILE, e); - } - } - } - - private void generateBashCompletion() { - if (configuration == null) { - log.log(Level.FINER, "Not writing Bash completion helper files. In order to generate these files please run some command which requires configuration."); - } else { - try { - File dir = new File(Constants.DIR, "bash-completion"); - dir.mkdir(); - writeBashCompletionHelperFile(configuration.getDatabases(), new File(dir, "databases")); - writeBashCompletionHelperFile(configuration.getAllFormatters(), new File(dir, "formatters")); - writeBashCompletionHelperFileForFormatterProperties(new File(dir, "formatter-properties")); - } catch (Exception e) { - log.log(Level.WARNING, "Unable to generate Bash completion helper files", e); - } - } - } - - private void writeBashCompletionHelperFile(Collection items, File target) throws FileNotFoundException { - if (Constants.CONFIG_FILE.lastModified() > target.lastModified()) { - try (PrintWriter fw = new PrintWriter(target)) { - for (NameIdentified dd : items) { - fw.println(dd.getName()); - } - fw.close(); - log.log(Level.FINE, "Bash completion helper file was written: {0}", target); - } - } else { - log.log(Level.FINER, "Not writing Bash completion helper file: {0} because configuration {1} has not been changed", new Object[]{target, Constants.CONFIG_FILE}); - } - } - - private void writeBashCompletionHelperFileForFormatterProperties(File formattersDir) throws ClassNotFoundException, FileNotFoundException { - if (Constants.CONFIG_FILE.lastModified() > formattersDir.lastModified()) { - // TODO: delete old directory - formattersDir.mkdir(); - for (FormatterDefinition fd : configuration.getAllFormatters()) { - File formatterDir = new File(formattersDir, fd.getName()); - formatterDir.mkdir(); - - Class formatterClass = (Class) Class.forName(fd.getClassName()); - List> hierarchy = Functions.getClassHierarchy(formatterClass, Formatter.class); - Collections.reverse(hierarchy); - for (Class c : hierarchy) { - for (PropertyDeclaration p : Functions.getPropertyDeclarations(c)) { - File propertyDir = new File(formatterDir, p.name()); - propertyDir.mkdir(); - File choicesFile = new File(propertyDir, "choices"); - try (PrintWriter fw = new PrintWriter(choicesFile)) { - // TODO: refactor, move - if (p.type() == Boolean.class) { - fw.println("true"); - fw.println("false"); - } - } - } - } - } - log.log(Level.FINE, "Bash completion helper files was written in: {0}", formattersDir); - } else { - log.log(Level.FINER, "Not writing Bash completion helper directory: {0} because configuration {1} has not been changed", new Object[]{formattersDir, Constants.CONFIG_FILE}); - } - - } -}