package com.linkedin.databus.util; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import com.linkedin.databus.core.BaseCli; /** * Command-line interface for {@link InteractiveSchemaGenerator} * <preformat> * usage: java com.linkedin.databus.util.InteractiveSchemaGenerator [options] * -A,--automatic Answer all questions proved through cli automatically and interactive for the rest of the options. * -b,--database <db_name> the name of database * -D,--dburl <url> DB URL to read view/table definitions * -f,--fields <fields> comma-separated list of table/view fields to include in the schema * -h,--help Prints command-line options info * -k,--pk <keys> comma-separated list of primary keys of view/table * -l,--log_props <property_file> Log4j properties to use * -p,--password <password> DB password * -q,--quiet turn off logging * -S,--schema_reg_path <path> path where to checkout the schema registry * -t,--table <table_name> name of the table/view whose schema to generate * -u,--username <user> DB username * -v verbose * -vv more verbose * -vvv most verbose * </preformat> */ public class InteractiveSchemaGeneratorCli extends BaseCli { private static char AUTOMATIC_OPT_CHAR = 'A'; private static char DBNAME_OPT_CHAR = 'b'; private static char DBURL_OPT_CHAR = 'D'; private static char FIELDS_OPT_CHAR = 'f'; private static char PK_OPT_CHAR = 'k'; private static char PASSWORD_OPT_CHAR = 'p'; private static char TABLE_OPT_CHAR = 't'; private static char USER_OPT_CHAR = 'u'; private static char SCHEMA_REGISTRY_PATH_OPT_CHAR = 'S'; private static char NUMBEROVERRIDE_OPT_CHAR = 'N'; private static String AUTOMATIC_OPT_NAME = "automatic"; private static String DBNAME_OPT_NAME = "database"; private static String DBURL_OPT_NAME = "dburl"; private static String FIELDS_OPT_NAME = "fields"; private static String PASSWORD_OPT_NAME = "password"; private static String PK_OPT_NAME = "pk"; private static String TABLE_OPT_NAME = "table"; private static String USER_OPT_NAME = "username"; private static String SCHEMA_REGISTRY_PATH_OPT_NAME = "schema_reg_path"; private static String NUMBEROVERRIDE_OPT_NAME = "number_override_map"; private boolean _automatic = Boolean.FALSE; private String _dbName; private String _dburl = InteractiveSchemaGenerator.DEFAULT_DATABASE; private List<String> _fields; private String _password; private List<String> _primaryKeys; private String _schemaRegPath = InteractiveSchemaGenerator.DEFAULT_SCHEMA_REGISTRY_LOCATION; private String _table; private String _user; private HashMap<String,String> _dbFieldToAvroDataType; public InteractiveSchemaGeneratorCli() { super(createDefaultUsageString(InteractiveSchemaGenerator.class), null); } @SuppressWarnings("static-access") @Override protected void constructCommandLineOptions() { super.constructCommandLineOptions(); Option automaticOption = OptionBuilder.withLongOpt(AUTOMATIC_OPT_NAME) .withDescription("Answer all questions proved through cli automatically and interactive for the rest of the options.") .create(AUTOMATIC_OPT_CHAR); Option dbnameOption = OptionBuilder.withLongOpt(DBNAME_OPT_NAME) .hasArg() .withArgName("db_name") .withDescription("The name of database") .create(DBNAME_OPT_CHAR); Option dburlOption = OptionBuilder.withLongOpt(DBURL_OPT_NAME) .hasArg() .withArgName("url") .withDescription("DB URL to read view/table definitions") .create(DBURL_OPT_CHAR); Option fieldsOption = OptionBuilder.withLongOpt(FIELDS_OPT_NAME) .hasArg() .withArgName("fields") .withDescription("Comma-separated list of table/view fields to include in the schema") .create(FIELDS_OPT_CHAR); Option passwordOption = OptionBuilder.withLongOpt(PASSWORD_OPT_NAME) .hasArg() .withArgName("password") .withDescription("DB password") .create(PASSWORD_OPT_CHAR); Option pkOption = OptionBuilder.withLongOpt(PK_OPT_NAME) .hasArg() .withArgName("keys") .withDescription("Comma-separated list of primary keys of view/table") .create(PK_OPT_CHAR); Option tableOption = OptionBuilder.withLongOpt(TABLE_OPT_NAME) .hasArg() .withArgName("table_name") .withDescription("The name of the table/view whose schema to generate ") .create(TABLE_OPT_CHAR); Option userOption = OptionBuilder.withLongOpt(USER_OPT_NAME) .hasArg() .withArgName("user") .withDescription("DB username") .create(USER_OPT_CHAR); Option schemaRegPathOption = OptionBuilder.withLongOpt(SCHEMA_REGISTRY_PATH_OPT_NAME) .hasArg() .withArgName("path") .withDescription("The path where to checkout the schema registry") .create(SCHEMA_REGISTRY_PATH_OPT_CHAR); Option numberOverrideOption = OptionBuilder.withLongOpt(NUMBEROVERRIDE_OPT_NAME) .hasArg() .withArgName("path") .withDescription("Override number fields datatype with FLOAT, LONG, INTEGER, DOUBLE. Input as, DB_FIELD_NAME1=FLOAT,DB_FIELD_NAME2=DOUBLE") .create(NUMBEROVERRIDE_OPT_CHAR); _cliOptions.addOption(automaticOption); _cliOptions.addOption(dbnameOption); _cliOptions.addOption(dburlOption); _cliOptions.addOption(fieldsOption); _cliOptions.addOption(passwordOption); _cliOptions.addOption(pkOption); _cliOptions.addOption(tableOption); _cliOptions.addOption(userOption); _cliOptions.addOption(schemaRegPathOption); _cliOptions.addOption(numberOverrideOption); } @Override public boolean processCommandLineArgs(String[] cliArgs) { boolean success = super.processCommandLineArgs(cliArgs); if (!success) { return false; } _automatic = _cmd.hasOption(AUTOMATIC_OPT_CHAR); if (_cmd.hasOption(DBNAME_OPT_CHAR)) { _dbName = _cmd.getOptionValue(DBNAME_OPT_CHAR).trim(); } if (_cmd.hasOption(DBURL_OPT_CHAR)) { _dburl = _cmd.getOptionValue(DBURL_OPT_CHAR).trim(); } if (_cmd.hasOption(FIELDS_OPT_CHAR)) { String fieldsStr = _cmd.getOptionValue(FIELDS_OPT_CHAR).trim(); String[] fields = fieldsStr.split("[, ]+"); _fields = Collections.unmodifiableList(Arrays.asList(fields)); } if (_cmd.hasOption(PASSWORD_OPT_CHAR)) { _password = _cmd.getOptionValue(PASSWORD_OPT_CHAR); } if (_cmd.hasOption(PK_OPT_CHAR)) { String pkStr = _cmd.getOptionValue(PK_OPT_CHAR).trim(); String[] pks = pkStr.split("[, ]+"); _primaryKeys = Collections.unmodifiableList(Arrays.asList(pks)); } if (_cmd.hasOption(TABLE_OPT_CHAR)) { _table = _cmd.getOptionValue(TABLE_OPT_CHAR).trim(); } if (_cmd.hasOption(USER_OPT_CHAR)) { _user = _cmd.getOptionValue(USER_OPT_CHAR).trim(); } if (_cmd.hasOption(SCHEMA_REGISTRY_PATH_OPT_CHAR)) { _schemaRegPath = _cmd.getOptionValue(SCHEMA_REGISTRY_PATH_OPT_CHAR).trim(); } if(_cmd.hasOption(NUMBEROVERRIDE_OPT_CHAR)) { _dbFieldToAvroDataType = new HashMap<String, String>(); String mapList = _cmd.getOptionValue(NUMBEROVERRIDE_OPT_CHAR).trim(); String[] mapElements = mapList.split(","); for(String mapElement : mapElements) { String[] dbFieldToDatatype = mapElement.split("="); _dbFieldToAvroDataType.put(dbFieldToDatatype[0].trim(), dbFieldToDatatype[1].trim()); } } return true; } /** For testing */ public static void main(String[] args) { for(int i=0;i <args.length ; i++) System.out.println("Arg["+i+"] = " + args[i]); String[] finalArgs; if(args.length > 1 && args[0].equals("-c")) //Python drive is going to pass all args in a "-c" { finalArgs = args[1].split("\\s"); } else { finalArgs = args; } InteractiveSchemaGeneratorCli cli = new InteractiveSchemaGeneratorCli(); if(!cli.processCommandLineArgs(finalArgs)) return; try { System.out.println("Starting the schema generation with cli options: "+ cli.toString()); InteractiveSchemaGenerator automaticSchemaGeneration = new InteractiveSchemaGenerator(cli); automaticSchemaGeneration.runSchemaGenTool(); } catch (Exception e) { System.out.println("Error running the schema generation tool"); e.printStackTrace(); } } /** The path to the schema registry */ public String getSchemaRegistryPath() { return _schemaRegPath; } /** Whether all questions should be answered automatically */ public boolean isAutomatic() { return _automatic; } /** The db url to read table/view definitions */ public String getDburl() { return _dburl; } /** DB user name */ public String getUser() { return _user; } /** DB password */ public String getPassword() { return _password; } /** The database/Oracle schema name*/ public String getDbName() { return _dbName; } /** Table/view name */ public String getTableName() { return _table; } /** Primary key(s) of the table/view*/ public List<String> getPrimaryKeys() { return _primaryKeys; } /** List of table/view fields to include in the generated schema */ public List<String> getFields() { return _fields; } @Override public String toString() { return "InteractiveSchemaGeneratorCli{" + "_automatic=" + _automatic + ", _dbName='" + _dbName + '\'' + ", _dburl='" + _dburl + '\'' + ", _fields=" + _fields + ", _password='" + _password + '\'' + ", _primaryKeys=" + _primaryKeys + ", _schemaRegPath='" + _schemaRegPath + '\'' + ", _table='" + _table + '\'' + ", _user='" + _user + '\'' + ", _dbFieldToAvroDataType=" + _dbFieldToAvroDataType + '}'; } public HashMap<String, String> getDbFieldToAvroDataType() { return _dbFieldToAvroDataType; } }