KNOX-2224 - KnoxLine and KnoxShell DataSource and Select Command Alignment (#255)

* KNOX-1742 - add to knoxshell usage rendering

* KNOX-2204 - KnoxLine NPE list datasources when directories don't exist

* KNOX-2224 - KnoxLine and KnoxShell DataSource and Select Command Alignment

Change-Id: I55aef2dd7617baf10c5f9eb7706f61436aa3ad7d
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Shell.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Shell.java
index bc681b0..6542dcb 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Shell.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Shell.java
@@ -19,6 +19,7 @@
 
 import groovy.ui.GroovyMain;
 
+import org.apache.knox.gateway.shell.commands.AbstractSQLCommandSupport;
 import org.apache.knox.gateway.shell.commands.CSVCommand;
 import org.apache.knox.gateway.shell.commands.DataSourceCommand;
 import org.apache.knox.gateway.shell.commands.SelectCommand;
@@ -61,6 +62,7 @@
     System.setProperty( "groovysh.prompt", "knox" );
   }
 
+  @SuppressWarnings("PMD.DoNotUseThreads") // we need to define a Thread to be able to register a shutdown hook
   public static void main( String... args ) throws Exception {
     PropertyConfigurator.configure( System.getProperty( "log4j.configuration" ) );
     if( args.length > 0 ) {
@@ -77,6 +79,16 @@
       }
     } else {
       Groovysh shell = new Groovysh();
+      Runtime.getRuntime().addShutdownHook(new Thread() {
+        @Override
+        public void run() {
+          System.out.println("Closing any open connections ...");
+          AbstractSQLCommandSupport sqlcmd = (AbstractSQLCommandSupport) shell.getRegistry().getProperty(":ds");
+          sqlcmd.closeConnections();
+          sqlcmd = (AbstractSQLCommandSupport) shell.getRegistry().getProperty(":sql");
+          sqlcmd.closeConnections();
+        }
+      });
       for( String name : IMPORTS ) {
         shell.execute( "import " + name );
       }
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/AbstractSQLCommandSupport.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/AbstractSQLCommandSupport.java
index c796be4..eaeea01 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/AbstractSQLCommandSupport.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/AbstractSQLCommandSupport.java
@@ -25,6 +25,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.knox.gateway.shell.CredentialCollectionException;
+import org.apache.knox.gateway.shell.CredentialCollector;
 import org.apache.knox.gateway.shell.KnoxDataSource;
 import org.apache.knox.gateway.shell.KnoxSession;
 import org.apache.knox.gateway.shell.jdbc.JDBCUtils;
@@ -182,4 +184,28 @@
     }
     return datasources;
   }
+
+  @SuppressWarnings("unchecked")
+  public void closeConnections() {
+    // close all JDBC connections in the session - called by shutdown hook
+    HashMap<String, Connection> connections =
+        (HashMap<String, Connection>) getVariables()
+        .getOrDefault(KNOXDATASOURCE_CONNECTIONS,
+            new HashMap<String, Connection>());
+    connections.values().forEach(connection->{
+      try {
+        if (!connection.isClosed()) {
+          connection.close();
+        }
+      } catch (SQLException e) {
+        // nop
+      }
+    });
+  }
+
+  protected CredentialCollector login() throws CredentialCollectionException {
+    KnoxLoginDialog dlg = new KnoxLoginDialog();
+    dlg.collect();
+    return dlg;
+  }
 }
\ No newline at end of file
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/DataSourceCommand.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/DataSourceCommand.java
index 818d1b2..4758df6 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/DataSourceCommand.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/DataSourceCommand.java
@@ -17,10 +17,14 @@
  */
 package org.apache.knox.gateway.shell.commands;
 
+import java.sql.Connection;
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.knox.gateway.shell.CredentialCollectionException;
+import org.apache.knox.gateway.shell.CredentialCollector;
 import org.apache.knox.gateway.shell.KnoxDataSource;
 import org.apache.knox.gateway.shell.table.KnoxShellTable;
 import org.codehaus.groovy.tools.shell.Groovysh;
@@ -31,7 +35,7 @@
     super(shell, ":datasources", ":ds");
   }
 
-  @SuppressWarnings("unchecked")
+  @SuppressWarnings({"unchecked", "PMD.CloseResource"})
   @Override
   public Object execute(List<String> args) {
     Map<String, KnoxDataSource> dataSources =
@@ -75,10 +79,36 @@
       if (dataSources == null || dataSources.isEmpty()) {
         return "No datasources to select from.";
       }
+      KnoxDataSource dsValue = dataSources.get(args.get(1));
+      Connection conn = getConnectionFromSession(dsValue);
+      try {
+        if (conn == null || conn.isClosed()) {
+          String username = null;
+          char[] pass = null;
+          if (dsValue.getAuthnType().equalsIgnoreCase("basic")) {
+            CredentialCollector dlg;
+            try {
+              dlg = login();
+            } catch (CredentialCollectionException e) {
+              e.printStackTrace();
+              return "Error: Credential collection failure.";
+            }
+            username = dlg.name();
+            pass = dlg.chars();
+          }
+          try {
+            getConnection(dsValue, username, new String(pass));
+          } catch (Exception e) {
+            e.printStackTrace();
+            return "Error: Connection creation failure.";
+          }
+        }
+      } catch (SQLException e) {
+        e.printStackTrace();
+      }
       if (dataSources.containsKey(args.get(1))) {
         getVariables().put(KNOXDATASOURCE, args.get(1));
       }
-      KnoxDataSource dsValue = dataSources.get(args.get(1));
       KnoxShellTable datasource = new KnoxShellTable();
       datasource.title("Knox DataSource Selected");
       datasource.header("Name").header("Connect String").header("Driver").header("Authn Type");
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/KnoxLoginDialog.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/KnoxLoginDialog.java
index fba19ef..90169e0 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/KnoxLoginDialog.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/KnoxLoginDialog.java
@@ -84,7 +84,7 @@
 
   @Override
   public String name() {
-    return name;
+    return username;
   }
 
   @Override
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/SelectCommand.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/SelectCommand.java
index d614cd1..d1de25e 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/SelectCommand.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/commands/SelectCommand.java
@@ -19,7 +19,10 @@
 
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
-import java.net.URISyntaxException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.List;
 import java.util.Map;
 
@@ -29,7 +32,7 @@
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 
-import org.apache.knox.gateway.shell.CredentialCollectionException;
+import org.apache.knox.gateway.shell.CredentialCollector;
 import org.apache.knox.gateway.shell.KnoxDataSource;
 import org.apache.knox.gateway.shell.table.KnoxShellTable;
 import org.codehaus.groovy.tools.shell.Groovysh;
@@ -82,7 +85,7 @@
   public void keyTyped(KeyEvent event) {
   }
 
-  @SuppressWarnings("unchecked")
+  @SuppressWarnings({"unchecked", "PMD.CloseResource"})
   @Override
   public Object execute(List<String> args) {
     boolean ok = false;
@@ -140,30 +143,33 @@
       //KnoxShellTable.builder().jdbc().connect("jdbc:derby:codejava/webdb1").driver("org.apache.derby.jdbc.EmbeddedDriver").username("lmccay").pwd("xxxx").sql("SELECT * FROM book");
       try {
         if (ok) {
-          if (ds.getAuthnType().equalsIgnoreCase("none")) {
-            table = KnoxShellTable.builder().jdbc()
-                .connectTo(ds.getConnectStr())
-                .driver(ds.getDriver())
-                .sql(sql);
-          }
-          else if (ds.getAuthnType().equalsIgnoreCase("basic")) {
-            KnoxLoginDialog dlg = new KnoxLoginDialog();
-            try {
-              dlg.collect();
-              if (dlg.ok) {
-                table = KnoxShellTable.builder().jdbc()
-                    .connectTo(ds.getConnectStr())
-                    .driver(ds.getDriver())
-                    .username(dlg.username)
-                    .password(new String(dlg.pass))
-                    .sql(sql);
+          System.out.println(sql);
+          try {
+            Connection conn = getConnectionFromSession(ds);
+            if (conn == null || conn.isClosed()) {
+              String username = null;
+              char[] pass = null;
+              if (ds.getAuthnType().equalsIgnoreCase("basic")) {
+                CredentialCollector dlg = login();
+                username = dlg.name();
+                pass = dlg.chars();
               }
-            } catch (CredentialCollectionException | URISyntaxException e) {
-              e.printStackTrace();
+              conn = getConnection(ds, username, new String(pass));
+            }
+            try (Statement statement = conn.createStatement()) {
+              if (statement.execute(sql)) {
+                try (ResultSet resultSet = statement.getResultSet()) {
+                  table = KnoxShellTable.builder().jdbc().resultSet(resultSet);
+                }
+              }
             }
           }
+          catch (SQLException e) {
+            System.out.println("SQL Exception encountered... " + e.getMessage());
+          }
         }
-      } catch (Exception e) {
+      }
+      catch (Exception e) {
         e.printStackTrace();
       }
     }
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/jdbc/KnoxLine.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/jdbc/KnoxLine.java
index 433c889..97a75c9 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/jdbc/KnoxLine.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/jdbc/KnoxLine.java
@@ -77,16 +77,19 @@
           // Configure JDBC connection
           if (datasource != null) {
             System.out.println(sql);
-            try (Statement statement = conn.createStatement()) {
-              if (statement.execute(sql)) {
-                try (ResultSet resultSet = statement.getResultSet()) {
-                  KnoxShellTable table = KnoxShellTable.builder().jdbc().resultSet(resultSet);
-                  System.out.println(table.toString());
-                  System.out.println("\nRows: " + table.getRows().size() + "\n");
+            try {
+              establishConnection();
+              try (Statement statement = conn.createStatement()) {
+                if (statement.execute(sql)) {
+                  try (ResultSet resultSet = statement.getResultSet()) {
+                    KnoxShellTable table = KnoxShellTable.builder().jdbc().resultSet(resultSet);
+                    System.out.println(table.toString());
+                    System.out.println("\nRows: " + table.getRows().size() + "\n");
+                  }
                 }
               }
             }
-            catch(SQLException e) {
+            catch (SQLException e) {
               System.out.println("SQL Exception encountered... " + e.getMessage());
             }
           }
@@ -100,6 +103,7 @@
 
   private void establishConnection() throws SQLException {
     if (conn == null || conn.isClosed()) {
+      System.out.println("Connecting...");
       conn = JDBCUtils.createConnection(datasource.getConnectStr(), user, pass);
     }
   }