/* * Copyright 2007-2012 Scott C. Gray * * 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. */ package org.sqsh.commands; import org.jline.reader.LineReader; import org.jline.reader.UserInterruptException; import org.sqsh.Command; import org.sqsh.ConnectionDescriptor; import org.sqsh.ConnectionDescriptorManager; import org.sqsh.SQLConnectionContext; import org.sqsh.SQLDriver; import org.sqsh.SQLDriver.DriverVariable; import org.sqsh.SQLDriverManager; import org.sqsh.SQLTools; import org.sqsh.Session; import org.sqsh.SqshOptions; import org.sqsh.analyzers.ANSIAnalyzer; import org.sqsh.analyzers.NullAnalyzer; import org.sqsh.analyzers.PLSQLAnalyzer; import org.sqsh.analyzers.SQLAnalyzer; import org.sqsh.analyzers.TSQLAnalyzer; import org.sqsh.normalizer.LowerCaseNormalizer; import org.sqsh.normalizer.NullNormalizer; import org.sqsh.normalizer.SQLNormalizer; import org.sqsh.normalizer.UpperCaseNormalizer; import org.sqsh.options.Argv; import org.sqsh.util.Ansi; import java.io.File; import java.io.PrintStream; import java.net.URL; import java.sql.Driver; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map.Entry; import java.util.Properties; public class Setup extends Command { private static class Options extends SqshOptions { @Argv(program="\\setup", min=0, max=1, usage=" [connections | drivers]") public List<String> arguments = new ArrayList<String>(); } @Override public SqshOptions getOptions() { return new Options(); } @Override public int execute(Session session, SqshOptions opts) throws Exception { Options options = (Options)opts; LineReader in = session.getContext().getConsole().getSimpleLineReader(); try { if (options.arguments.size() > 0) { String path = options.arguments.get(0); if (path.equals("connections")) { doConnectionWizard(session, session.out, in); } else if (path.equals("drivers")) { doDriverWizard(session, session.out, in); } else { session.err.println("Unrecognized setup type \"" + path + "\""); } } else { doWelcome(session, session.out, in); } } catch (UserInterruptException e) { session.err.println("Aborting setup"); return 1; } return 0; } public void doWelcome(Session session, PrintStream out, LineReader in) throws Exception { boolean done = false; while (! done) { cls(in); out.println("JSQSH SETUP WIZARD"); out.println(); out.println("Welcome to the jsqsh setup wizard! This wizard provides a (crude) menu"); out.println("driven interface for managing several jsqsh configuration files. These"); out.println("files are all located in $HOME/.jsqsh, and the name of the file being"); out.println("edited by a given screen will be indicated on the title of the screen"); out.println(); out.println("Note that many wizard screens require a relative large console screen"); out.println("size, so you may want to resize your screen now."); out.println(); out.println("(C)onnection management wizard"); out.println(" The connection management wizard allows you to define named connections"); out.println(" using any JDBC driver that jsqsh recognizes. Once defined, jsqsh only"); out.println(" needs the connection name in order to establish a JDBC connection"); out.println(); out.println("(D)river management wizard"); out.println(" The driver management wizard allows you to introduce new JDBC drivers"); out.println(" to jsqsh, or to edit the definition of an existing driver. The most"); out.println(" common activity here is to provide the classpath for a given JDBC driver"); out.println(); String str = readline(in, "Choose (Q)uit, (C)onnection wizard, or (D)river wizard: "); str = str.trim(); if ("q".equalsIgnoreCase(str) || "b".equalsIgnoreCase(str)) { done = true; } else if ("d".equalsIgnoreCase(str)) { done = doDriverWizard(session, out, in); } else if ("c".equalsIgnoreCase(str)) { done = doConnectionWizard(session, out, in); } } out.println(); out.println("You may re-enter the jsqsh setup wizard at any time with the \\setup command"); out.println("or by starting jsqsh with the --setup option"); out.println(); } public boolean doConnectionWizard(Session session, PrintStream out, LineReader in) throws Exception { SQLDriverManager driverMan = session.getDriverManager(); boolean done = false; boolean doQuit = false; while (! done) { cls(in); session.out.println("JSQSH CONNECTION WIZARD - (edits $HOME/.jsqsh/connections.xml"); ConnectionDescriptor []connDescs = session.getConnectionDescriptorManager().getAll(); Arrays.sort(connDescs); if (connDescs == null || connDescs.length == 0) { done = doConnectionChooseDriver(session, out, in); continue; } else { out.println("The following connections are currently defined:"); out.println(); out.println(" Name Driver Host Port"); out.println("--- -------------------- ---------- ------------------------------ ------"); boolean hasStar = false; for (int i = 0; i < connDescs.length; i++) { ConnectionDescriptor desc = connDescs[i]; SQLDriver driver = driverMan.getDriver(desc.getDriver()); if (desc.isAutoconnect()) { hasStar = true; } String server = desc.getServer(); if (server == null) { server = driver.getVariable(SQLDriver.SERVER_PROPERTY); } server = limit(server, 30); int port = desc.getPort(); String portStr = null; if (port < 0) { portStr = driver.getVariable(SQLDriver.PORT_PROPERTY); if (portStr == null) { portStr = "-"; } } else { portStr = Integer.toString(port); } out.printf("%3d %s%-20s %-10s %-30s %6s\n", i+1, desc.isAutoconnect() ? "*" : " ", limit(desc.getName(), 20), limit(desc.getDriver(), 10), server, portStr); } if (hasStar) { out.println(); out.println(" * = Connection is set for autoconnect"); } } out.println(); if (connDescs == null || connDescs.length > 0) { out.println("Enter a connection number above to edit the connection, or:"); } out.flush(); String str = readline(in, "(B)ack, (Q)uit, or (A)dd connection: "); str = str.trim(); if (str.equalsIgnoreCase("b")) { done = true; } else if (str.equalsIgnoreCase("q")) { doQuit = done = true; } else if (str.equalsIgnoreCase("a")) { doQuit = doConnectionChooseDriver(session, out, in); done = doQuit; } else { int id = toInt(str); if (id >= 1 && id <= connDescs.length) { doQuit = doConfigConnection(session, out, in, connDescs[id-1], driverMan.getDriver(connDescs[id-1].getDriver())); done = doQuit; } } } return doQuit; } /** * Render the "add" screen * @throws Exception */ public boolean doConnectionChooseDriver(Session session, PrintStream out, LineReader in) throws Exception { SQLDriverManager driverMan = session.getDriverManager(); boolean done = false; boolean doQuit = false; List<SQLDriver> drivers = new ArrayList<SQLDriver>(); List<SQLDriver> unavail = new ArrayList<SQLDriver>(); SQLDriver all[] = driverMan.getDrivers(); Arrays.sort(all); for (int i = 0; i < all.length; i++) { if (all[i].isAvailable()) { drivers.add(all[i]); } else { unavail.add(all[i]); } } drivers.addAll(unavail); while (!done) { cls(in); out.println("JSQSH CONNECTION WIZARD - (edits $HOME/.jsqsh/connections.xml)"); out.println(); out.println("Choose a driver for use by your new connection"); out.println(); out.println(" Name Target Class"); out.println("--- ---------------- -------------------- --------------------------------------------------"); for (int i = 0; i < drivers.size(); i++) { SQLDriver driver = drivers.get(i); out.printf("%3d %s%-15s %-20s %-50s\n", i+1, (driver.isAvailable() ? "*" : " "), crop(driver.getName(), 15), crop(driver.getTarget(), 20), limitFront(driver.getDriverClass(), 50)); } out.println(); out.println(" * = Driver is availabe. If a driver is unavailable you may choose (D) below "); out.println(" to jump to the driver wizard to provide a classpath"); out.println(); out.flush(); String str = readline(in, "Enter the driver number, (D)river wizard, (B)ack or (Q)uit: "); str = str.trim(); if (str.equalsIgnoreCase("b")) { done = true; } else if (str.equalsIgnoreCase("q")) { done = true; doQuit = true; } else if (str.equalsIgnoreCase("d")) { doQuit = doDriverWizard(session, out, in); if (doQuit) { done = true; } } else { int driver = toInt(str); if (driver >= 1 && driver <= drivers.size()) { doQuit = doConfigConnection(session, out, in, null, drivers.get(driver-1)); done = true; } } } return doQuit; } public boolean doConfigConnection(Session session, PrintStream out, LineReader in, ConnectionDescriptor conDesc, SQLDriver driver) throws Exception { boolean doQuit = false; boolean done = false; boolean isNew = (conDesc == null); if (conDesc == null) { conDesc = new ConnectionDescriptor("_temp_"); conDesc.setDriver(driver.getName()); } else { conDesc = (ConnectionDescriptor) conDesc.clone(); } List<DriverVariable> vars = driver.getVariableDescriptions(); int longestName = 0; for (int i = 0; i < vars.size(); i++) { String name = vars.get(i).getDisplayName(); if (name.length() > longestName) { longestName = name.length(); } } if (longestName < 15) { longestName = 15; } String format = "%-3d %" + longestName + "s : %s\n"; while (! done) { cls(in); out.println("JSQSH CONNECTION WIZARD - (edits $HOME/.jsqsh/connections.xml)"); out.println(); out.println("The following configuration properties are supported by this driver."); out.println(); out.printf(" %" + longestName + "s : %s\n", "Connection name", conDesc.getName()); out.printf(" %" + longestName + "s : %s\n", "Driver", driver.getTarget()); out.printf(" %" + longestName + "s : %s\n", "JDBC URL", driver.getUrl()); out.println(); out.println("Connection URL Variables"); out.println("------------------------"); if (vars.size() == 0) { out.println("None"); } int idx = 0; for (; idx < vars.size(); idx++) { DriverVariable var = vars.get(idx); String value = conDesc.getValueOf(var.getName()); if (value == null) { value = var.getDefaultValue(); } if (value != null && var.getName().equals("password")) { String stars = ""; for (int j = 0; j < value.length(); j++) { stars = stars + "*"; } value = stars; } out.printf(format, idx+1, vars.get(idx).getName(), value == null ? "" : value); } out.printf(format, idx+1, "Autoconnect", (conDesc.isAutoconnect() ? "true" : "false")); int autoConnectAt = idx++; out.println(); out.println("JDBC Driver Properties"); out.println("------------------------"); String props[] = conDesc.getPropertiesMap().keySet().toArray(new String[0]); if (props.length == 0) { out.println("None"); } Arrays.sort(props); int propsStartAt = idx; for (int i = 0; i < props.length; i++) { out.printf(format, idx+1, props[i], conDesc.getPropertiesMap().get(props[i])); ++idx; } out.println(); out.println("Enter a number to change a given configuration property, or"); out.flush(); String prompt = (isNew ? "(T)est, (B)ack, (Q)uit, Add (P)roperty, or (S)ave: " : "(T)est, (D)elete, (B)ack, (Q)uit, Add (P)roperty, or (S)ave: "); String str = readline(in, prompt); str = str.trim(); if (str.equalsIgnoreCase("b")) { done = true; } if (str.equalsIgnoreCase("q")) { done = true; doQuit = true; } if (str.equalsIgnoreCase("t")) { doTest(session, out, in, conDesc); } if (! isNew && str.equalsIgnoreCase("d")) { ConnectionDescriptorManager connMan = session.getConnectionDescriptorManager(); out.println(); str = readline(in, "Are you sure (Y/N)? "); if ("y".equalsIgnoreCase(str)) { connMan.remove(conDesc.getName()); connMan.save(); done = true; } } if (str.equalsIgnoreCase("s")) { out.println(); boolean doSave = true; if (conDesc.getName().equals("_temp_")) { str = ""; while (str.length() == 0) { str = readline(in, "Please provide a connection name: "); str = str.trim(); } conDesc.setName(str); } else { str = readline(in, "Are you sure (Y/N)? "); doSave = "y".equalsIgnoreCase(str); } if (doSave) { ConnectionDescriptorManager connMan = session.getConnectionDescriptorManager(); connMan.put(conDesc); connMan.save(); done = true; } } if (str.equalsIgnoreCase("p")) { // Hack to re-used the JDBC driver property screen SQLDriver drv = session.getDriverManager().getDriver(conDesc.getDriver()).copy(); drv.getDriverProperties().clear(); newDriverProperty(session, out, in, drv); for (Entry<String, String> e : drv.getDriverProperties().entrySet()) { conDesc.setProperty(e.getKey(), e.getValue()); } } else { int val = toInt(str); if (val >= 1 && val <= vars.size()) { DriverVariable var = vars.get(val-1); boolean isPassword = var.getName().equals(SQLDriver.PASSWORD_PROPERTY); out.println(); out.println("Please enter a new value:"); if (isPassword) { str = in.readLine(var.getName() + ": ", '*'); } else { str = readline(in, var.getName() + ": "); } str = str.trim(); conDesc.setValueOf(var.getName(), str); } else if (val == autoConnectAt+1) { conDesc.setAutoconnect(! conDesc.isAutoconnect()); } else if (props.length > 0 && val >= propsStartAt && val <= propsStartAt + props.length) { String prop = props[(val-1) - propsStartAt]; out.println(); out.println("An empty value removes the property definition"); str = readline(in, "Enter new value for \"" + prop + "\": "); str = str.trim(); if (str.length() == 0) { conDesc.removeProperty(prop); } else { conDesc.setProperty(prop, str); } } } } return doQuit; } private static void doTest(Session session, PrintStream out, LineReader in, ConnectionDescriptor connDesc) throws Exception { SQLDriverManager driverMan = session.getDriverManager(); try { out.println(); out.println("Attempting connection..."); SQLConnectionContext conn = driverMan.connect(session, connDesc); conn.close(); out.println("Succeeded!"); } catch (SQLException e) { out.println("Failed!"); SQLTools.printException(session, e); } catch (Throwable e) { out.println("Failed!"); session.printException(e); } out.println(); readline(in, "Hit enter to continue:"); } public boolean doDriverWizard(Session session, PrintStream out, LineReader in) throws Exception { boolean done = false; boolean doQuit = false; SQLDriverManager driverMan = session.getDriverManager(); while (!done) { SQLDriver []drivers = driverMan.getDrivers(); Arrays.sort(drivers); cls(in); out.println("JSQSH DRIVER WIZARD - (edits $HOME/.jsqsh/drivers.xml)"); out.println(); out.println("The following drivers are currently defined:"); out.println(); out.println(" Name Target Class"); out.println("--- --------------- -------------------- --------------------------------------------------"); for (int i = 0; i < drivers.length; i++) { SQLDriver driver = drivers[i]; out.printf("%-3d %s%-15s %-20s %-50s\n", i+1, driver.isAvailable() ? "*" : " ", crop(driver.getName(), 15), crop(driver.getTarget(), 20), crop(driver.getDriverClass(), 50)); } out.println(); out.println(" * = Driver is available"); out.println(); out.println("Enter a number to change an existing driver, or:"); out.flush(); String str = readline(in, "(B)ack, (Q)uit, or (A)dd new driver: "); str = str.trim(); if ("q".equalsIgnoreCase(str)) { done = true; doQuit = true; } else if ("b".equalsIgnoreCase(str)) { done = true; } else if ("a".equalsIgnoreCase(str)) { doQuit = doEditDriver (session, out, in, null); done = doQuit; } else { int id = toInt(str); if (id >= 1 && id <= drivers.length) { doQuit = doEditDriver (session, out, in, drivers[id-1]); done = doQuit; } } } return doQuit; } private boolean doEditDriver (Session session, PrintStream out, LineReader in, SQLDriver origDriver) throws Exception { boolean isNewDriver = (origDriver == null); SQLDriver driver = null; boolean doSave = false; if (origDriver == null) { driver = new SQLDriver(); } else { driver = origDriver.copy(); } boolean done = false; boolean doQuit = false; while (! done) { cls(in); out.println("JDBC WIZARD DRIVER EDITOR - (edits $HOME/.jsqsh/drivers.xml)"); out.println(); out.println("The following are standard driver configuration variables for jsqsh JDBC URL's:"); out.println(" ${server}, ${port}, ${db}, ${domain}, ${user}, ${password}"); out.println("You may also define your own variables by placing them in the URL"); out.println(); out.println("Example URL: jdbc:db2://${server}:${port}/${db}"); out.println(); out.println("Base Configuration"); out.println("---------------------"); int idx = 0; String format = "%-2d %s %15s : %s\n"; String promptFormat = "%-2d %s %15s : "; int nameIdx = ++idx; if (driver.getName() == null) { driver.setName(getEntry(out, in, String.format(promptFormat, nameIdx, "*", "Name"), true)); } else { out.format(format, nameIdx, "*", "Name", driver.getName()); } int descriptionIdx = ++idx; if (driver.getTarget() == null) { driver.setTarget(getEntry(out, in, String.format(promptFormat, descriptionIdx, "*", "Description"), true)); } else { out.format(format, descriptionIdx, "*", "Description", driver.getTarget()); } int classIdx = ++idx; if (driver.getDriverClass() == null) { driver.setDriverClass(getEntry(out, in, String.format(promptFormat, classIdx, "*", "Class"), true)); } else { out.format(format, classIdx, "*", "Class", driver.getDriverClass()); } int urlIdx = ++idx; if (driver.getUrl() == null) { driver.setUrl(getEntry(out, in, String.format(promptFormat, urlIdx, "*", "URL"), true)); } else { out.format(format, urlIdx, "*", "URL", driver.getUrl()); } int analyzerIdx = ++idx; out.format(format, analyzerIdx, " ", "SQL Parser", driver.getAnalyzer().getName()); int classpathIdx = ++idx; out.format(format, classpathIdx, " ", "Classpath", driver.getClasspath()); int normalizerIdx = ++idx; out.format(format, normalizerIdx, " ", "Name normalizer", driver.getNormalizer().getName()); int schemaQueryIdx = ++idx; out.format(format, schemaQueryIdx, " ", "Schema query", driver.getCurrentSchemaQuery() == null ? "(none)" : driver.getCurrentSchemaQuery()); out.format(" %15s : %s\n", "Status", driverStatus(session, driver)); out.println(); out.println("URL Variable Defaults"); out.println("---------------------"); List<DriverVariable> vars = driver.getVariableDescriptions(false); int variableStartIdx = 0; int variableEndIdx = 0; for (int i = 0; i < vars.size(); i++) { DriverVariable var = vars.get(i); ++idx; variableEndIdx = idx; if (i == 0) { variableStartIdx = idx; } out.format(format, idx, " ", var.getName(), emptyIfNull(var.getDefaultValue())); } out.println(); out.println("Enter a number to change a existing driver, or:"); out.flush(); String prompt = (isNewDriver ? "(B)ack, (Q)uit, Show (C)lasspath, (A)dvanced options, or (S)ave: " : "(B)ack, (Q)uit, (D)elete, Show (C)lasspath, (A)dvanced options, or (S)ave: "); String str = readline(in, prompt); str = str.trim(); if ("q".equalsIgnoreCase(str)) { done = true; doQuit = true; } else if ("b".equalsIgnoreCase(str)) { done = true; } else if ("c".equalsIgnoreCase(str)) { out.println("Driver computed classpath: "); List<URL> urls = driver.getExpandedClasspath(); for (URL url : urls) { out.println(" " + url); } out.println(); readline(in, "Hit enter to continue: "); } else if ("a".equalsIgnoreCase(str)) { ScreenReturn ret = doEditDriverAdvanced(session, out, in, driver); if (ret == ScreenReturn.SAVE) { done = true; doSave = true; } else if (ret == ScreenReturn.QUIT) { done = doQuit = true; } } else if (! isNewDriver && "d".equalsIgnoreCase(str)) { out.println(); str = readline(in, "Are you sure (Y/N)? "); if ("y".equalsIgnoreCase(str)) { SQLDriverManager driverMan = session.getDriverManager(); driverMan.removeDriver(origDriver.getName()); driverMan.save(new File(session.getContext().getConfigDirectory(), "drivers.xml")); done = true; } } else if ("s".equalsIgnoreCase(str)) { done = true; doSave = true; } else { int opt = toInt(str); if (opt >= 1 && opt <= idx) { if (opt == nameIdx) { out.println(); driver.setName(getEntry(out, in, "Enter new name: ", true)); } else if (opt == descriptionIdx) { out.println(); driver.setTarget(getEntry(out, in, "Enter new description: ", true)); } else if (opt == classIdx) { out.println(); driver.setDriverClass(getEntry(out, in, "Enter new class: ", true)); } else if (opt == urlIdx) { out.println(); driver.setUrl(getEntry(out, in, "Enter new URL: ", true)); } else if (opt == analyzerIdx) { driver.setAnalyzer(chooseAnalyzer(out, in)); } else if (opt == classpathIdx) { out.println(); driver.setClasspath(getEntry(out, in, "Enter new classpath: ", false)); } else if (opt == normalizerIdx) { out.println(); driver.setNormalizer(chooseNormalizer(out, in)); } else if (opt == schemaQueryIdx) { out.println(); driver.setCurrentSchemaQuery(getEntry(out, in, "Enter query to fetch current schema: ", false)); } else if (opt >= variableStartIdx && opt <= variableEndIdx) { DriverVariable var = vars.get(opt - variableStartIdx); out.println(); str = readline(in, "Enter new value for \"" + var.getName() + "\": "); str = str.trim(); if (str.length() == 0) { driver.removeVariable(var.getName()); } else { driver.setVariable(var.getName(), str); } } } } } if (doSave) { SQLDriverManager driverMan = session.getDriverManager(); /* * Check for a driver rename. Note that renaming an internal driver * cannot ever really get rid of it. */ if (! isNewDriver && ! origDriver.getName().equals(driver.getName())) { driverMan.removeDriver(origDriver.getName()); } driverMan.addDriver(driver); driverMan.save(new File(session.getContext().getConfigDirectory(), "drivers.xml")); } return doQuit; } private ScreenReturn doEditDriverAdvanced (Session session, PrintStream out, LineReader in, SQLDriver driver) throws Exception { while (true) { cls(in); out.println("JDBC DRIVER EDITOR - ADVANCED OPTIONS"); out.println(); out.println("Driver Information"); out.println("---------------------"); String format = " %15s : %s\n"; out.format(format, "Name", driver.getName()); out.format(format, "Description", driver.getTarget()); out.format(format, "Class", driver.getDriverClass()); out.format(format, "URL", driver.getUrl()); out.println(); out.println("Session variables to set upon connect"); out.println("--------------------------------------"); out.println("The following jsqsh variables will be set upon connecting to the data source"); out.println("These may be used to change the prompt, or to affect jsqsh configuration changes"); out.println(); String sessionVars[] = driver.getSessionVariables().keySet().toArray(new String[0]); Arrays.sort(sessionVars); if (sessionVars.length == 0) { out.println("None"); } int idx = 1; format = "%-2d %s %15s : %s\n"; for (int i = 0; i < sessionVars.length; i++) { out.format(format, idx++, "", sessionVars[i], driver.getSessionVariable(sessionVars[i])); } int driverPropsStartAt = idx; out.println(); out.println("JDBC driver connection properties"); out.println("--------------------------------------"); out.println("The following are configuration properties specific to this JDBC driver"); out.println(); String driverProps[] = driver.getDriverProperties().keySet().toArray(new String[0]); Arrays.sort(driverProps); if (driverProps.length == 0) { out.println("None"); } format = "%-2d %s %15s : %s\n"; for (int i = 0; i < driverProps.length; i++) { out.format(format, idx++, "", driverProps[i], driver.getProperty(driverProps[i])); } out.println(); out.println("Enter a number to change a existing setting, or:"); out.flush(); String str = readline(in, "(B)ack, (Q)uit, New (V)ariable, New (P)roperty, or (S)ave: "); str = str.trim(); if ("q".equalsIgnoreCase(str)) { return ScreenReturn.QUIT; } else if ("b".equalsIgnoreCase(str)) { return ScreenReturn.BACK; } else if ("s".equalsIgnoreCase(str)) { return ScreenReturn.SAVE; } else if ("v".equalsIgnoreCase(str)) { out.println(); String name = readline(in, "Session variable name: "); String value = readline(in, "Session variable value: "); name = name.trim(); value = value.trim(); if (value.length() > 0) { driver.setSessionVariable(name, value); } } else if ("p".equalsIgnoreCase(str)) { newDriverProperty(session, out, in, driver); } else { int opt = toInt(str); if (opt >= 1 && opt < driverPropsStartAt) { String var = sessionVars[opt-1]; out.println(); out.println("An empty value removes the variable definition"); str = readline(in, "Enter new value for \"" + var + "\": "); str = str.trim(); if (str.length() == 0) { driver.removeSessionVariable(var); } else { driver.setSessionVariable(var, str); } } else if (opt >= driverPropsStartAt && opt < idx) { String var = driverProps[opt - driverPropsStartAt]; out.println(); out.println("An empty value removes the property definition"); str = readline(in, "Enter new value for \"" + var + "\": "); str = str.trim(); if (str.length() == 0) { driver.removeProperty(var); } else { driver.setProperty(var, str); } } } } } private SQLAnalyzer chooseAnalyzer(PrintStream out, LineReader in) throws Exception { out.println(); out.println("1. None"); out.println("2. ANSI SQL"); out.println("3. PL/SQL"); out.println("4. T-SQL"); while (true) { String str = readline(in, "Choose a SQL analyzer: "); str = str.trim(); int id = toInt(str); if (id < 1 || id > 4) { killLine(in); } else { switch (id) { case 1: return new NullAnalyzer(); case 2: return new ANSIAnalyzer(); case 3: return new PLSQLAnalyzer(); case 4: return new TSQLAnalyzer(); default: break; } } } } private SQLNormalizer chooseNormalizer(PrintStream out, LineReader in) throws Exception { out.println(); out.println("1. NONE"); out.println("2. UPPER CASE"); out.println("3. LOWER CASE"); while (true) { String str = readline(in, "Select object name normalization for this database: "); str = str.trim(); int id = toInt(str); if (id < 1 || id > 3) { killLine(in); } else { switch (id) { case 1: return new NullNormalizer(); case 2: return new UpperCaseNormalizer(); case 3: return new LowerCaseNormalizer(); default: break; } } } } private void newDriverProperty(Session session, PrintStream out, LineReader in, SQLDriver driver) throws Exception { DriverPropertyInfo info[] = null; try { ClassLoader loader = driver.getClassLoader(session.getDriverManager().getClassLoader()); Class<? extends Driver> driverClass = loader.loadClass(driver.getDriverClass()).asSubclass(Driver.class); Driver driverInst = driverClass.newInstance(); info = driverInst.getPropertyInfo(driver.getUrl(), new Properties()); } catch (Throwable e) { /* SILENTLY IGNORED */ System.out.println(e.getMessage()); } if (info == null) { out.println("Available driver properties could not be retrieved (this may happen"); out.println("if the JDBC driver cannot be loaded), you may manually enter properties."); out.println("Note: property values may refer to environment variables or jsqsh"); out.println("variable values:"); String name = readline(in, "Property name: "); String value = readline(in, "Property value: "); name = name.trim(); value = value.trim(); if (value.length() > 0) { driver.setProperty(name, value); } return; } boolean done = false; while (! done) { cls(in); out.println("DRIVER PROPERTIES"); out.println(); out.println("The following properties are published by the driver. Note that "); out.println("not all properties may be published by your driver, and you may "); out.println("manually enter a property if needed."); out.println(); int halfIdx = (info.length / 2); if ((info.length - halfIdx) > halfIdx) { ++halfIdx; } int longest = 0; for (int i = 0; i < halfIdx; i++) { if (info[i].name.length() > longest) { longest = info[i].name.length(); } } String leftFormat = "%-2d %-" + longest + "s "; String rightFormat = "%-2d %s\n"; int leftIdx = 0; int rightIdx = halfIdx; while (leftIdx < halfIdx) { out.format(leftFormat, leftIdx+1, info[leftIdx].name); if (rightIdx < info.length) { out.format(rightFormat, rightIdx+1, info[rightIdx].name); } else { out.println(); } ++leftIdx; ++rightIdx; } out.println(); out.println("Enter a property number to edit that property. A question mark after"); out.println("the property name (e.g. \"2?\") will display a description, if available: "); String str = readline(in, "(M)anually enter, or (B)ack: "); str = str.trim(); if (str.equalsIgnoreCase("b")) { done = true; } else if (str.equalsIgnoreCase("m")) { done = true; out.println(); out.println("Note: Property values may refer to environment variables or jsqsh variable values"); out.println(); String name = readline(in, "Property name: "); String value = readline(in, "Property value: "); name = name.trim(); value = value.trim(); if (value.length() > 0) { driver.setProperty(name, value); } } else { if (str.endsWith("?")) { str = str.substring(0, str.length()-1); int idx = toInt(str); out.println(); if (idx >= 1 || idx <= info.length) { if (info[idx-1].description != null && info[idx].description.length() > 0) { out.println(info[idx-1].description); } else { out.println("No help is avalable"); } out.println(); readline(in, "Hit enter to continue: "); continue; } } int idx = toInt(str); if (idx >= 1 && idx <= info.length) { if (info[idx-1].choices == null || info[idx-1].choices.length == 0) { String value = readline(in, "New value for \"" + info[idx-1].name + "\": "); value = value.trim(); if (value.length() > 0) { driver.setProperty(info[idx-1].name, value); } done = true; } else { out.println(); String choices[] = info[idx-1].choices; String format = "%-2d %s\n"; for (int i = 0; i < choices.length; i++) { out.format(format, (i+1), choices[i]); } out.println(); while (! done) { str = readline(in, "Enter choice or (B)ack: "); str = str.trim(); if ("b".equalsIgnoreCase(str)) { break; } else if (str.length() > 0) { int choice = toInt(str); if (choice >= 1 && choice < choices.length) { done = true; driver.setProperty(info[idx-1].name, choices[choice-1]); } } if (! done) { killLine(in); } } } } } } } private String driverStatus(Session session, SQLDriver driver) { try { ClassLoader loader = driver.getClassLoader(session.getDriverManager().getClassLoader()); loader.loadClass(driver.getDriverClass()); return "Available"; } catch (Throwable e) { return "Cannot load driver class (" + e.getMessage() + ")"; } } private String getEntry(PrintStream out, LineReader in, String prompt, boolean isRequired) throws Exception { String str = ""; while (str.length() == 0) { str = readline(in, prompt); str = str.trim(); if (! isRequired) { if (str.length() == 0) { str = null; } break; } if (str.length() == 0) { } } return str; } public static String emptyIfNull(String str) { if (str == null) { return ""; } return str; } public static int toInt(String str) { try { return Integer.valueOf(str); } catch (NumberFormatException e) { return -1; } } public static String crop(String str, int len) { if (str != null && str.length() > len) { str = str.substring(0, len); } return str; } public static String limit(String str, int len) { if (str != null && str.length() > len) { str = str.substring(0, len - 3) + "..."; } return str; } public static String limitFront(String str, int len) { if (str != null && str.length() > len) { str = "..." + str.substring(0, len - 3); } return str; } private static String readline(LineReader in, String prompt) { return in.readLine(prompt); } private void cls(LineReader in) { // Clear screen, cursor to 0,0 in.getTerminal().writer().write(Ansi.clearScreen()); in.getTerminal().writer().write(Ansi.cursorMove(0,0)); in.getTerminal().writer().flush();; } private void killLine(LineReader in) { // Cursor up 1, erase line, cursor up 1 in.getTerminal().writer().write(Ansi.cursorUp(1)); in.getTerminal().writer().write(Ansi.clearToEnd()); in.getTerminal().writer().write(Ansi.cursorUp(1)); in.getTerminal().writer().flush(); } private static enum ScreenReturn { BACK, QUIT, SAVE } }