java/sql-dk/src/info/globalcode/sql/dk/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Mon, 23 Dec 2013 11:50:24 +0100
branchv_0
changeset 37 9e6f8e5d5f98
parent 29 d66858b4b563
child 44 67581ec4396e
permissions -rw-r--r--
support SQL commands returning more ResultSets + remove COMMAND_TYPE (type is now derived from result returned from SQL – it is not needed to specify the type on CLI)
     1 /**
     2  * SQL-DK
     3  * Copyright © 2013 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 package info.globalcode.sql.dk;
    19 
    20 import java.sql.Types;
    21 import java.util.ArrayList;
    22 import java.util.Collections;
    23 import java.util.HashMap;
    24 import java.util.List;
    25 import java.util.Map;
    26 
    27 /**
    28  *
    29  * @author Ing. František Kučera (frantovo.cz)
    30  */
    31 public class CLIParser {
    32 
    33 	public static final String TYPE_NAME_SEPARATOR = ":";
    34 	private final Map<String, Integer> types;
    35 
    36 	public CLIParser() {
    37 		Map<String, Integer> m = new HashMap<>();
    38 		m.put("int", Types.INTEGER);
    39 		m.put("string", Types.VARCHAR);
    40 		m.put("boolean", Types.BOOLEAN);
    41 		/**
    42 		 * TODO: more types
    43 		 */
    44 		types = Collections.unmodifiableMap(m);
    45 	}
    46 
    47 	public CLIOptions parseOptions(String[] args) throws CLIParserException {
    48 		CLIOptions options = new CLIOptions();
    49 
    50 		List<Integer> numberedTypes = new ArrayList<>();
    51 		Map<String, Integer> namedTypes = new HashMap<>();
    52 
    53 		for (int i = 0; i < args.length; i++) {
    54 			String arg = args[i];
    55 			switch (arg) {
    56 				case Tokens.TYPES:
    57 					String typesString = fetchNext(args, ++i);
    58 
    59 					for (String oneType : typesString.split(",")) {
    60 						int sepatratorIndex = oneType.indexOf(TYPE_NAME_SEPARATOR);
    61 						if (sepatratorIndex == -1) {
    62 							numberedTypes.add(getType(oneType));
    63 						} else {
    64 							String namePart = oneType.substring(0, sepatratorIndex).trim();
    65 							String typePart = oneType.substring(sepatratorIndex + TYPE_NAME_SEPARATOR.length(), oneType.length());
    66 							namedTypes.put(namePart, getType(typePart));
    67 						}
    68 					}
    69 					break;
    70 				case Tokens.NAME_PREFIX:
    71 					options.setNamePrefix(fetchNext(args, ++i));
    72 					break;
    73 				case Tokens.DB:
    74 					options.setDatabaseName(fetchNext(args, ++i));
    75 					break;
    76 				case Tokens.SQL:
    77 					options.setSql(fetchNext(args, ++i));
    78 					break;
    79 				case Tokens.BATCH:
    80 					options.setBatch(true);
    81 					break;
    82 				case Tokens.DATA: // --data is the last option
    83 					for (i++; i < args.length; i++) {
    84 						arg = args[i];
    85 
    86 						if (arg.startsWith(options.getNamePrefix())) { // Named parameters:
    87 							String paramName = arg.substring(options.getNamePrefix().length());
    88 							String paramValue = fetchNext(args, ++i);
    89 							options.addNamedParameter(new NamedParameter(paramName, paramValue, namedTypes.get(paramName)));
    90 						} else { // Numbered parameters:
    91 							Parameter parameter;
    92 							if (numberedTypes.isEmpty()) {
    93 								parameter = new Parameter(arg, null);
    94 							} else {
    95 								int paramIndex = options.getNumberedParameters().size();
    96 								int paramType;
    97 								try {
    98 									paramType = numberedTypes.get(paramIndex);
    99 								} catch (IndexOutOfBoundsException e) {
   100 									throw new CLIParserException("Missing type for parameter #" + paramIndex, e);
   101 								} catch (NullPointerException e) {
   102 									throw new CLIParserException("Invalid type definition for parameter #" + paramIndex, e);
   103 								}
   104 								parameter = new Parameter(arg, paramType);
   105 							}
   106 							options.addNumberedParameter(parameter);
   107 						}
   108 					}
   109 					break;
   110 				case Tokens.FORMATTER:
   111 					options.setFormatterName(fetchNext(args, ++i));
   112 					break;
   113 				case Tokens.INFO_HELP:
   114 					options.addShowInfo(CLIOptions.INFO_TYPE.HELP);
   115 					break;
   116 				case Tokens.INFO_FORMATTERS:
   117 					options.addShowInfo(CLIOptions.INFO_TYPE.FORMATTERS);
   118 					break;
   119 				case Tokens.INFO_LICENSE:
   120 					options.addShowInfo(CLIOptions.INFO_TYPE.LICENSE);
   121 					break;
   122 				case Tokens.INFO_TYPES:
   123 					options.addShowInfo(CLIOptions.INFO_TYPE.TYPES);
   124 					break;
   125 				case Tokens.INFO_VERSION:
   126 					options.addShowInfo(CLIOptions.INFO_TYPE.VERSION);
   127 					break;
   128 				case Tokens.INFO_DATABASES:
   129 					options.addShowInfo(CLIOptions.INFO_TYPE.DATABASES);
   130 					break;
   131 				case Tokens.INFO_CONNECTION:
   132 					options.addShowInfo(CLIOptions.INFO_TYPE.CONNECTION);
   133 					options.setDatabaseNameToTest(fetchNext(args, ++i));
   134 					break;
   135 				default:
   136 					throw new CLIParserException("Unknown option: " + arg);
   137 			}
   138 		}
   139 		return options;
   140 	}
   141 
   142 	private String fetchNext(String[] args, int index) throws CLIParserException {
   143 		if (index < args.length) {
   144 			return args[index];
   145 		} else {
   146 			throw new CLIParserException("Expecting value for option: " + args[index - 1]);
   147 		}
   148 	}
   149 
   150 	public static class Tokens {
   151 
   152 		public static final String DB = "--db";
   153 		public static final String SQL = "--sql";
   154 		public static final String BATCH = "--batch";
   155 		public static final String DATA = "--data";
   156 		public static final String NAME_PREFIX = "--name-prefix";
   157 		public static final String TYPES = "--types";
   158 		public static final String FORMATTER = "--formatter";
   159 		public static final String INFO_HELP = "--help";
   160 		public static final String INFO_VERSION = "--version";
   161 		public static final String INFO_LICENSE = "--license";
   162 		public static final String INFO_FORMATTERS = "--list-formatters";
   163 		public static final String INFO_TYPES = "--list-types";
   164 		public static final String INFO_DATABASES = "--list-databases";
   165 		public static final String INFO_CONNECTION = "--test-connection";
   166 
   167 		private Tokens() {
   168 		}
   169 	}
   170 
   171 	private int getType(String typeString) throws CLIParserException {
   172 		Integer type = types.get(typeString.trim());
   173 		if (type == null) {
   174 			throw new CLIParserException("Unsupported type: " + typeString);
   175 		} else {
   176 			return type;
   177 		}
   178 	}
   179 }