All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hive.jdbc.Utils Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.hive.jdbc;

import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hive.service.cli.HiveSQLException;
import org.apache.hive.service.rpc.thrift.TStatus;
import org.apache.hive.service.rpc.thrift.TStatusCode;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Utils {
  static final Logger LOG = LoggerFactory.getLogger(Utils.class.getName());
  /**
    * The required prefix for the connection URL.
    */
  public static final String URL_PREFIX = "jdbc:hive2://";

  /**
    * If host is provided, without a port.
    */
  static final String DEFAULT_PORT = "10000";

  // To parse the intermediate URI as a Java URI, we'll give a dummy authority(dummyhost:00000).
  // Later, we'll substitute the dummy authority for a resolved authority.
  static final String dummyAuthorityString = "dummyhost:00000";

  /**
   * Hive's default database name
   */
  static final String DEFAULT_DATABASE = "default";

  private static final String URI_JDBC_PREFIX = "jdbc:";

  private static final String URI_HIVE_PREFIX = "hive2:";

  // This value is set to true by the setServiceUnavailableRetryStrategy() when the server returns 401.
  // This value is used only when cookie is sent for authorization. In case the cookie is expired,
  // client will send the actual credentials in the next connection request.
  // If credentials are sent in the first request it self, then no need to retry.
  static final String HIVE_SERVER2_RETRY_KEY = "hive.server2.retryserver";
  static final String HIVE_SERVER2_SENT_CREDENTIALS = "hive.server2.sentCredentials";
  static final String HIVE_SERVER2_CONST_TRUE = "true";
  static final String HIVE_SERVER2_CONST_FALSE = "false";

  public static class JdbcConnectionParams {
    // Note on client side parameter naming convention:
    // Prefer using a shorter camelCase param name instead of using the same name as the
    // corresponding
    // HiveServer2 config.
    // For a jdbc url: jdbc:hive2://:/dbName;sess_var_list?hive_conf_list#hive_var_list,
    // client side params are specified in sess_var_list

    // Client param names:

    // Retry setting
    public static final String RETRIES = "retries";
    public static final String RETRY_INTERVAL = "retryInterval";

    public static final String AUTH_TYPE = "auth";
    // We're deprecating this variable's name.
    public static final String AUTH_QOP_DEPRECATED = "sasl.qop";
    public static final String AUTH_QOP = "saslQop";
    public static final String AUTH_SIMPLE = "noSasl";
    public static final String AUTH_TOKEN = "delegationToken";
    public static final String AUTH_USER = "user";
    public static final String AUTH_PRINCIPAL = "principal";
    public static final String AUTH_PASSWD = "password";
    public static final String AUTH_KERBEROS_AUTH_TYPE = "kerberosAuthType";
    public static final String AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT = "fromSubject";
    // JdbcConnection param which specifies if we need to use a browser to do
    // authentication.
    // JdbcConnectionParam which specifies if the authMode is done via a browser
    public static final String AUTH_SSO_BROWSER_MODE = "browser";
    public static final String AUTH_SSO_TOKEN_MODE = "token";
    // connection parameter used to specify a port number to listen on in case of
    // browser mode.
    public static final String AUTH_BROWSER_RESPONSE_PORT = "browserResponsePort";
    // connection parameter used to specify the timeout in seconds for the browser mode
    public static final String AUTH_BROWSER_RESPONSE_TIMEOUT_SECS = "browserResponseTimeout";
    // connection parameter to optionally disable the SSL validation done when using
    // browser based authentication. Useful mostly for testing/dev purposes.
    // By default, SSL validation is done unless this parameter is set to true.
    public static final String AUTH_BROWSER_DISABLE_SSL_VALIDATION = "browserDisableSslCheck";
    public static final String ANONYMOUS_USER = "anonymous";
    public static final String ANONYMOUS_PASSWD = "anonymous";
    public static final String USE_SSL = "ssl";
    public static final String SSL_TRUST_STORE = "sslTrustStore";
    public static final String SSL_TRUST_STORE_PASSWORD = "trustStorePassword";
    public static final String SSL_TRUST_STORE_TYPE = "trustStoreType";
    public static final String SSL_TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm";
    // We're deprecating the name and placement of this in the parsed map (from hive conf vars to
    // hive session vars).
    static final String TRANSPORT_MODE_DEPRECATED = "hive.server2.transport.mode";
    public static final String TRANSPORT_MODE = "transportMode";
    // We're deprecating the name and placement of this in the parsed map (from hive conf vars to
    // hive session vars).
    static final String HTTP_PATH_DEPRECATED = "hive.server2.thrift.http.path";
    public static final String HTTP_PATH = "httpPath";
    public static final String SERVICE_DISCOVERY_MODE = "serviceDiscoveryMode";
    public static final String PROPERTY_DRIVER        = "driver";
    public static final String PROPERTY_URL           = "url";
    // Don't use dynamic service discovery
    static final String SERVICE_DISCOVERY_MODE_NONE = "none";
    // Use ZooKeeper for indirection while using dynamic service discovery
    public static final String SERVICE_DISCOVERY_MODE_ZOOKEEPER = "zooKeeper";
    public static final String SERVICE_DISCOVERY_MODE_ZOOKEEPER_HA = "zooKeeperHA";
    public static final String ZOOKEEPER_NAMESPACE = "zooKeeperNamespace";
    public static final String ZOOKEEPER_SSL_ENABLE = "zooKeeperSSLEnable";
    public static final String ZOOKEEPER_KEYSTORE_LOCATION = "zooKeeperKeystoreLocation";
    public static final String ZOOKEEPER_KEYSTORE_PASSWORD= "zooKeeperKeystorePassword";
    public static final String ZOOKEEPER_TRUSTSTORE_LOCATION  = "zooKeeperTruststoreLocation";
    public static final String ZOOKEEPER_TRUSTSTORE_PASSWORD = "zooKeeperTruststorePassword";
    // Default namespace value on ZooKeeper.
    // This value is used if the param "zooKeeperNamespace" is not specified in the JDBC Uri.
    static final String ZOOKEEPER_DEFAULT_NAMESPACE = "hiveserver2";
    static final String ZOOKEEPER_ACTIVE_PASSIVE_HA_DEFAULT_NAMESPACE = "hs2ActivePassiveHA";
    static final String COOKIE_AUTH = "cookieAuth";
    static final String COOKIE_AUTH_FALSE = "false";
    static final String COOKIE_NAME = "cookieName";
    // The default value of the cookie name when CookieAuth=true
    static final String DEFAULT_COOKIE_NAMES_HS2 = "hive.server2.auth";
    // The http header prefix for additional headers which have to be appended to the request
    static final String HTTP_HEADER_PREFIX = "http.header.";
    // Set the fetchSize
    static final String FETCH_SIZE = "fetchSize";
    static final String INIT_FILE = "initFile";
    static final String WM_POOL = "wmPool";
    // Cookie prefix
    static final String HTTP_COOKIE_PREFIX = "http.cookie.";
    // Create external purge table by default
    static final String CREATE_TABLE_AS_EXTERNAL = "hiveCreateAsExternalLegacy";
    public static final String SOCKET_TIMEOUT = "socketTimeout";

    // We support ways to specify application name modeled after some existing DBs, since
    // there's no standard approach.
    // MSSQL: applicationName https://docs.microsoft.com/en-us/sql/connect/jdbc/building-the-connection-url
    // Postgres 9~: ApplicationName https://jdbc.postgresql.org/documentation/91/connect.html
    // Note: various ODBC names used include "Application Name", "APP", etc. Add those?
    static final String[] APPLICATION = new String[] { "applicationName", "ApplicationName" };

    // --------------- Begin 2 way ssl options -------------------------
    // Use two way ssl. This param will take effect only when ssl=true
    static final String USE_TWO_WAY_SSL = "twoWay";
    static final String TRUE = "true";
    static final String SSL_KEY_STORE = "sslKeyStore";
    static final String SSL_KEY_STORE_PASSWORD = "keyStorePassword";
    static final String SSL_KEY_STORE_TYPE = "JKS";
    static final String SUNX509_ALGORITHM_STRING = "SunX509";
    static final String SUNJSSE_ALGORITHM_STRING = "SunJSSE";
   // --------------- End 2 way ssl options ----------------------------

    private static final String HIVE_VAR_PREFIX = "hivevar:";
    public static final String HIVE_CONF_PREFIX = "hiveconf:";
    private String host = null;
    private int port = 0;
    private String jdbcUriString;
    private String dbName = DEFAULT_DATABASE;
    private Map hiveConfs = new LinkedHashMap();
    private Map hiveVars = new LinkedHashMap();
    private Map sessionVars = new LinkedHashMap();
    private boolean isEmbeddedMode = false;
    private String suppliedURLAuthority;
    private String zooKeeperEnsemble = null;
    private boolean zooKeeperSslEnabled = false;
    private String zookeeperKeyStoreLocation = "";
    private String zookeeperKeyStorePassword = "";
    private String zookeeperTrustStoreLocation = "";
    private String zookeeperTrustStorePassword = "";
    private String currentHostZnodePath;
    private final List rejectedHostZnodePaths = new ArrayList();

    // HiveConf parameters
    public static final String HIVE_DEFAULT_NULLS_LAST_KEY =
        HIVE_CONF_PREFIX + HiveConf.ConfVars.HIVE_DEFAULT_NULLS_LAST.varname;

    public JdbcConnectionParams() {
    }

    public JdbcConnectionParams(JdbcConnectionParams params) {
      this.host = params.host;
      this.port = params.port;
      this.jdbcUriString = params.jdbcUriString;
      this.dbName = params.dbName;
      this.hiveConfs.putAll(params.hiveConfs);
      this.hiveVars.putAll(params.hiveVars);
      this.sessionVars.putAll(params.sessionVars);
      this.isEmbeddedMode = params.isEmbeddedMode;
      this.suppliedURLAuthority = params.suppliedURLAuthority;
      this.zooKeeperEnsemble = params.zooKeeperEnsemble;
      this.zooKeeperSslEnabled = params.zooKeeperSslEnabled;
      this.zookeeperKeyStoreLocation = params.zookeeperKeyStoreLocation;
      this.zookeeperKeyStorePassword = params.zookeeperKeyStorePassword;
      this.zookeeperTrustStoreLocation = params.zookeeperTrustStoreLocation;
      this.zookeeperTrustStorePassword = params.zookeeperTrustStorePassword;

      this.currentHostZnodePath = params.currentHostZnodePath;
      this.rejectedHostZnodePaths.addAll(rejectedHostZnodePaths);
    }

    public String getHost() {
      return host;
    }

    public int getPort() {
      return port;
    }

    public String getJdbcUriString() {
      return jdbcUriString;
    }

    public String getDbName() {
      return dbName;
    }

    public Map getHiveConfs() {
      return hiveConfs;
    }

    public Map getHiveVars() {
      return hiveVars;
    }

    public boolean isEmbeddedMode() {
      return isEmbeddedMode;
    }

    public Map getSessionVars() {
      return sessionVars;
    }

    public String getSuppliedURLAuthority() {
      return suppliedURLAuthority;
    }

    public String getZooKeeperEnsemble() {
      return zooKeeperEnsemble;
    }
    public boolean isZooKeeperSslEnabled() {
      return zooKeeperSslEnabled;
    }

    public String getZookeeperKeyStoreLocation() {
      return zookeeperKeyStoreLocation;
    }

    public String getZookeeperKeyStorePassword() {
      return zookeeperKeyStorePassword;
    }

    public String getZookeeperTrustStoreLocation() {
      return zookeeperTrustStoreLocation;
    }

    public String getZookeeperTrustStorePassword() {
      return zookeeperTrustStorePassword;
    }

    public List getRejectedHostZnodePaths() {
      return rejectedHostZnodePaths;
    }

    public String getCurrentHostZnodePath() {
      return currentHostZnodePath;
    }

    public void setHost(String host) {
      this.host = host;
    }

    public void setPort(int port) {
      this.port = port;
    }

    public void setJdbcUriString(String jdbcUriString) {
      this.jdbcUriString = jdbcUriString;
    }

    public void setDbName(String dbName) {
      this.dbName = dbName;
    }

    public void setHiveConfs(Map hiveConfs) {
      this.hiveConfs = hiveConfs;
    }

    public void setHiveVars(Map hiveVars) {
      this.hiveVars = hiveVars;
    }

    public void setEmbeddedMode(boolean embeddedMode) {
      this.isEmbeddedMode = embeddedMode;
    }

    public void setSessionVars(Map sessionVars) {
      this.sessionVars = sessionVars;
    }

    public void setSuppliedURLAuthority(String suppliedURLAuthority) {
      this.suppliedURLAuthority = suppliedURLAuthority;
    }

    public void setZooKeeperEnsemble(String zooKeeperEnsemble) {
      this.zooKeeperEnsemble = zooKeeperEnsemble;
    }

    public void setZooKeeperSslEnabled(boolean zooKeeperSslEnabled) {
      this.zooKeeperSslEnabled = zooKeeperSslEnabled;
    }

    public void setZookeeperKeyStoreLocation(String zookeeperKeyStoreLocation) {
      this.zookeeperKeyStoreLocation = zookeeperKeyStoreLocation;
    }

    public void setZookeeperKeyStorePassword(String zookeeperKeyStorePassword) {
      this.zookeeperKeyStorePassword = zookeeperKeyStorePassword;
    }

    public void setZookeeperTrustStoreLocation(String zookeeperTrustStoreLocation) {
      this.zookeeperTrustStoreLocation = zookeeperTrustStoreLocation;
    }

    public void setZookeeperTrustStorePassword(String zookeeperTrustStorePassword) {
      this.zookeeperTrustStorePassword = zookeeperTrustStorePassword;
    }

    public void setCurrentHostZnodePath(String currentHostZnodePath) {
      this.currentHostZnodePath = currentHostZnodePath;
    }
  }

  // Verify success or success_with_info status, else throw SQLException
  static void verifySuccessWithInfo(TStatus status) throws SQLException {
    verifySuccess(status, true);
  }

  // Verify success status, else throw SQLException
  static void verifySuccess(TStatus status) throws SQLException {
    verifySuccess(status, false);
  }

  // Verify success and optionally with_info status, else throw SQLException
  static void verifySuccess(TStatus status, boolean withInfo) throws SQLException {
    if (status.getStatusCode() == TStatusCode.SUCCESS_STATUS ||
        (withInfo && status.getStatusCode() == TStatusCode.SUCCESS_WITH_INFO_STATUS)) {
      return;
    }
    throw new HiveSQLException(status);
  }

  public static JdbcConnectionParams parseURL(String uri) throws JdbcUriParseException,
          SQLException, ZooKeeperHiveClientException {
    return parseURL(uri, new Properties());
  }
  /**
   * Parse JDBC connection URL
   * The new format of the URL is:
   * jdbc:hive2://<host1>:<port1>,<host2>:<port2>/dbName;sess_var_list?hive_conf_list#hive_var_list
   * where the optional sess, conf and var lists are semicolon separated <key>=<val> pairs.
   * For utilizing dynamic service discovery with HiveServer2 multiple comma separated host:port pairs can
   * be specified as shown above.
   * The JDBC driver resolves the list of uris and picks a specific server instance to connect to.
   * Currently, dynamic service discovery using ZooKeeper is supported, in which case the host:port pairs represent a ZooKeeper ensemble.
   *
   * As before, if the host/port is not specified, it the driver runs an embedded hive.
   * examples -
   *  jdbc:hive2://ubuntu:11000/db2?hive.cli.conf.printheader=true;hive.exec.mode.local.auto.inputbytes.max=9999#stab=salesTable;icol=customerID
   *  jdbc:hive2://?hive.cli.conf.printheader=true;hive.exec.mode.local.auto.inputbytes.max=9999#stab=salesTable;icol=customerID
   *  jdbc:hive2://ubuntu:11000/db2;user=foo;password=bar
   *
   *  Connect to http://server:10001/hs2, with specified basicAuth credentials and initial database:
   *  jdbc:hive2://server:10001/db;user=foo;password=bar?hive.server2.transport.mode=http;hive.server2.thrift.http.path=hs2
   *
   * @param uri
   * @return
   * @throws SQLException
   */
  public static JdbcConnectionParams parseURL(String uri, Properties info)
      throws JdbcUriParseException, SQLException, ZooKeeperHiveClientException {
    JdbcConnectionParams connParams = extractURLComponents(uri, info);
    if (ZooKeeperHiveClientHelper.isZkDynamicDiscoveryMode(connParams.getSessionVars())) {
      configureConnParamsFromZooKeeper(connParams);
    }
    handleAllDeprecations(connParams);
    return connParams;
  }

  /**
   * This method handles the base parsing of the given jdbc uri. Some of JdbcConnectionParams
   * returned from this method are updated if ZooKeeper is used for service discovery
   *
   * @param uri
   * @param info
   * @return
   * @throws JdbcUriParseException
   */
  public static JdbcConnectionParams extractURLComponents(String uri, Properties info)
      throws JdbcUriParseException {
    JdbcConnectionParams connParams = new JdbcConnectionParams();
    if (!uri.startsWith(URL_PREFIX)) {
      throw new JdbcUriParseException("Bad URL format: Missing prefix " + URL_PREFIX);
    }

    // For URLs with no other configuration
    // Don't parse them, but set embedded mode as true
    if (uri.equalsIgnoreCase(URL_PREFIX)) {
      connParams.setEmbeddedMode(true);
      return connParams;
    }

    // The JDBC URI now supports specifying multiple host:port if dynamic service discovery is
    // configured on HiveServer2 (like: host1:port1,host2:port2,host3:port3)
    // We'll extract the authorities (host:port combo) from the URI, extract session vars, hive
    // confs & hive vars by parsing it as a Java URI.
    String authorityFromClientJdbcURL = getAuthorityFromJdbcURL(uri);
    if ((authorityFromClientJdbcURL == null) || (authorityFromClientJdbcURL.isEmpty())) {
      // Given uri of the form:
      // jdbc:hive2:///dbName;sess_var_list?hive_conf_list#hive_var_list
      connParams.setEmbeddedMode(true);
    } else {
      connParams.setSuppliedURLAuthority(authorityFromClientJdbcURL);
      uri = uri.replace(authorityFromClientJdbcURL, dummyAuthorityString);
    }

    // Now parse the connection uri with dummy authority
    URI jdbcURI = URI.create(uri.substring(URI_JDBC_PREFIX.length()));

    // key=value pattern
    Pattern pattern = Pattern.compile("([^;]*)=([^;]*)[;]?");

    // dbname and session settings
    String sessVars = jdbcURI.getPath();
    if ((sessVars != null) && !sessVars.isEmpty()) {
      String dbName = "";
      // removing leading '/' returned by getPath()
      sessVars = sessVars.substring(1);
      if (!sessVars.contains(";")) {
        // only dbname is provided
        dbName = sessVars;
      } else {
        // we have dbname followed by session parameters
        dbName = sessVars.substring(0, sessVars.indexOf(';'));
        sessVars = sessVars.substring(sessVars.indexOf(';') + 1);
        if (sessVars != null) {
          Matcher sessMatcher = pattern.matcher(sessVars);
          while (sessMatcher.find()) {
            if (connParams.getSessionVars().put(sessMatcher.group(1),
                sessMatcher.group(2)) != null) {
              throw new JdbcUriParseException(
                  "Bad URL format: Multiple values for property " + sessMatcher.group(1));
            }
          }
        }
      }
      if (!dbName.isEmpty()) {
        connParams.setDbName(dbName);
      }
    }

    // parse hive conf settings
    String confStr = jdbcURI.getQuery();
    if (confStr != null) {
      Matcher confMatcher = pattern.matcher(confStr);
      while (confMatcher.find()) {
        connParams.getHiveConfs().put(confMatcher.group(1), confMatcher.group(2));
      }
    }

    // parse hive var settings
    String varStr = jdbcURI.getFragment();
    if (varStr != null) {
      Matcher varMatcher = pattern.matcher(varStr);
      while (varMatcher.find()) {
        connParams.getHiveVars().put(varMatcher.group(1), varMatcher.group(2));
      }
    }

    // Apply configs supplied in the JDBC connection properties object
    for (Map.Entry kv : info.entrySet()) {
      if ((kv.getKey() instanceof String)) {
        String key = (String) kv.getKey();
        if (key.startsWith(JdbcConnectionParams.HIVE_VAR_PREFIX)) {
          connParams.getHiveVars().put(key.substring(JdbcConnectionParams.HIVE_VAR_PREFIX.length()),
              info.getProperty(key));
        } else if (key.startsWith(JdbcConnectionParams.HIVE_CONF_PREFIX)) {
          connParams.getHiveConfs().put(
              key.substring(JdbcConnectionParams.HIVE_CONF_PREFIX.length()), info.getProperty(key));
        }
      }
    }

    // Extract user/password from JDBC connection properties if its not supplied
    // in the connection URL
    if (!connParams.getSessionVars().containsKey(JdbcConnectionParams.AUTH_USER)) {
      if (info.containsKey(JdbcConnectionParams.AUTH_USER)) {
        connParams.getSessionVars().put(JdbcConnectionParams.AUTH_USER,
            info.getProperty(JdbcConnectionParams.AUTH_USER));
      }
      if (info.containsKey(JdbcConnectionParams.AUTH_PASSWD)) {
        connParams.getSessionVars().put(JdbcConnectionParams.AUTH_PASSWD,
            info.getProperty(JdbcConnectionParams.AUTH_PASSWD));
      }
    }

    if (!connParams.getSessionVars().containsKey(JdbcConnectionParams.AUTH_PASSWD)) {
      if (info.containsKey(JdbcConnectionParams.AUTH_USER)) {
        connParams.getSessionVars().put(JdbcConnectionParams.AUTH_USER,
                info.getProperty(JdbcConnectionParams.AUTH_USER));
      }
      if (info.containsKey(JdbcConnectionParams.AUTH_PASSWD)) {
        connParams.getSessionVars().put(JdbcConnectionParams.AUTH_PASSWD,
                info.getProperty(JdbcConnectionParams.AUTH_PASSWD));
      }
    }

    if (info.containsKey(JdbcConnectionParams.AUTH_TYPE)) {
      connParams.getSessionVars().put(JdbcConnectionParams.AUTH_TYPE,
          info.getProperty(JdbcConnectionParams.AUTH_TYPE));
    }
    // Extract host, port
    if (connParams.isEmbeddedMode()) {
      // In case of embedded mode we were supplied with an empty authority.
      // So we never substituted the authority with a dummy one.
      connParams.setHost(jdbcURI.getHost());
      connParams.setPort(jdbcURI.getPort());
    } else {
      String authorityStr = connParams.getSuppliedURLAuthority();
      // If we're using ZooKeeper, the final host, port will be read from ZooKeeper
      // (in a different method call). Therefore, we put back the original authority string
      // (which basically is the ZooKeeper ensemble) back in the uri
      if (ZooKeeperHiveClientHelper.isZkDynamicDiscoveryMode(connParams.getSessionVars())) {
        uri = uri.replace(dummyAuthorityString, authorityStr);
        // Set ZooKeeper ensemble in connParams for later use
        connParams.setZooKeeperEnsemble(authorityStr);
        ZooKeeperHiveClientHelper.setZkSSLParams(connParams);
      } else {
        URI jdbcBaseURI = URI.create(URI_HIVE_PREFIX + "//" + authorityStr);
        // Check to prevent unintentional use of embedded mode. A missing "/"
        // to separate the 'path' portion of URI can result in this.
        // The missing "/" common typo while using secure mode, eg of such url -
        // jdbc:hive2://localhost:10000;principal=hive/[email protected]
        if (jdbcBaseURI.getAuthority() != null) {
          String host = jdbcBaseURI.getHost();
          int port = jdbcBaseURI.getPort();
          if (host == null) {
            throw new JdbcUriParseException(
                "Bad URL format. Hostname not found " + " in authority part of the url: "
                    + jdbcBaseURI.getAuthority() + ". Are you missing a '/' after the hostname ?");
          }
          // Set the port to default value; we do support jdbc url like:
          // jdbc:hive2://localhost/db
          if (port <= 0) {
            port = Integer.parseInt(Utils.DEFAULT_PORT);
          }
          connParams.setHost(jdbcBaseURI.getHost());
          connParams.setPort(jdbcBaseURI.getPort());
        }
        // We check for invalid host, port while configuring connParams with configureConnParams()
        authorityStr = connParams.getHost() + ":" + connParams.getPort();
        LOG.debug("Resolved authority: " + authorityStr);
        uri = uri.replace(dummyAuthorityString, authorityStr);
      }
    }
    connParams.setJdbcUriString(uri);
    return connParams;
  }

  // Configure using ZooKeeper
  static void configureConnParamsFromZooKeeper(JdbcConnectionParams connParams)
      throws ZooKeeperHiveClientException, JdbcUriParseException {
    ZooKeeperHiveClientHelper.configureConnParams(connParams);
    String authorityStr = connParams.getHost() + ":" + connParams.getPort();
    LOG.debug("Resolved authority: " + authorityStr);
    String jdbcUriString = connParams.getJdbcUriString();
    // Replace ZooKeeper ensemble from the authority component of the JDBC Uri provided by the
    // client, by the host:port of the resolved server instance we will connect to
    connParams.setJdbcUriString(
        jdbcUriString.replace(getAuthorityFromJdbcURL(jdbcUriString), authorityStr));
  }

  private static void handleAllDeprecations(JdbcConnectionParams connParams) {
    // Handle all deprecations here:
    String newUsage;
    String usageUrlBase = "jdbc:hive2://:/dbName;";
    // Handle deprecation of AUTH_QOP_DEPRECATED
    newUsage = usageUrlBase + JdbcConnectionParams.AUTH_QOP + "=";
    handleParamDeprecation(connParams.getSessionVars(), connParams.getSessionVars(),
        JdbcConnectionParams.AUTH_QOP_DEPRECATED, JdbcConnectionParams.AUTH_QOP, newUsage);

    // Handle deprecation of TRANSPORT_MODE_DEPRECATED
    newUsage = usageUrlBase + JdbcConnectionParams.TRANSPORT_MODE + "=";
    handleParamDeprecation(connParams.getHiveConfs(), connParams.getSessionVars(),
        JdbcConnectionParams.TRANSPORT_MODE_DEPRECATED, JdbcConnectionParams.TRANSPORT_MODE,
        newUsage);

    // Handle deprecation of HTTP_PATH_DEPRECATED
    newUsage = usageUrlBase + JdbcConnectionParams.HTTP_PATH + "=";
    handleParamDeprecation(connParams.getHiveConfs(), connParams.getSessionVars(),
        JdbcConnectionParams.HTTP_PATH_DEPRECATED, JdbcConnectionParams.HTTP_PATH, newUsage);
  }

  /**
   * Remove the deprecatedName param from the fromMap and put the key value in the toMap.
   * Also log a deprecation message for the client.
   * @param fromMap
   * @param toMap
   * @param deprecatedName
   * @param newName
   * @param newUsage
   */
  private static void handleParamDeprecation(Map fromMap, Map toMap,
      String deprecatedName, String newName, String newUsage) {
    if (fromMap.containsKey(deprecatedName)) {
      LOG.warn("***** JDBC param deprecation *****");
      LOG.warn("The use of " + deprecatedName + " is deprecated.");
      LOG.warn("Please use " + newName +" like so: " + newUsage);
      String paramValue = fromMap.remove(deprecatedName);
      toMap.put(newName, paramValue);
    }
  }

  /**
   * Get the authority string from the supplied uri, which could potentially contain multiple
   * host:port pairs.
   *
   * @param uri
   * @return
   * @throws JdbcUriParseException
   */
  private static String getAuthorityFromJdbcURL(String uri) throws JdbcUriParseException {
    String authorities;
    /**
     * For a jdbc uri like:
     * jdbc:hive2://:,:/dbName;sess_var_list?conf_list#var_list Extract
     * the uri host:port list starting after "jdbc:hive2://", till the 1st "/" or "?" or "#"
     * whichever comes first & in the given order Examples:
     * jdbc:hive2://host1:port1,host2:port2,host3:port3/db;k1=v1?k2=v2#k3=v3
     * jdbc:hive2://host1:port1,host2:port2,host3:port3/;k1=v1?k2=v2#k3=v3
     * jdbc:hive2://host1:port1,host2:port2,host3:port3?k2=v2#k3=v3
     * jdbc:hive2://host1:port1,host2:port2,host3:port3#k3=v3
     */
    int fromIndex = Utils.URL_PREFIX.length();
    int toIndex = -1;
    for (String toIndexChar : Arrays.asList("/", "?", "#")) {
      toIndex = uri.indexOf(toIndexChar, fromIndex);
      if (toIndex > 0) {
        break;
      }
    }
    if (toIndex < 0) {
      authorities = uri.substring(fromIndex);
    } else {
      authorities = uri.substring(fromIndex, toIndex);
    }
    return authorities;
  }

  /**
   * Read the next server coordinates (host:port combo) from ZooKeeper. Ignore the znodes already
   * explored. Also update the host, port, jdbcUriString and other configs published by the server.
   *
   * @param connParams
   * @return true if new server info is retrieved successfully
   */
  static boolean updateConnParamsFromZooKeeper(JdbcConnectionParams connParams) {
    // Add current host to the rejected list
    connParams.getRejectedHostZnodePaths().add(connParams.getCurrentHostZnodePath());
    String oldServerHost = connParams.getHost();
    int oldServerPort = connParams.getPort();
    // Update connection params (including host, port) from ZooKeeper
    try {
      ZooKeeperHiveClientHelper.configureConnParams(connParams);
      connParams.setJdbcUriString(connParams.getJdbcUriString().replace(
          oldServerHost + ":" + oldServerPort, connParams.getHost() + ":" + connParams.getPort()));
      LOG.info("Selected HiveServer2 instance with uri: " + connParams.getJdbcUriString());
    } catch(ZooKeeperHiveClientException e) {
      LOG.error(e.getMessage());
      return false;
    }

    return true;
  }

  /**
   * Takes a version string delimited by '.' and '-' characters
   * and returns a partial version.
   *
   * @param fullVersion
   *          version string.
   * @param position
   *          position of version string to get starting at 0. eg, for a X.x.xxx
   *          string, 0 will return the major version, 1 will return minor
   *          version.
   * @return version part, or -1 if version string was malformed.
   */
  static int getVersionPart(String fullVersion, int position) {
    int version = -1;
    try {
      String[] tokens = fullVersion.split("[\\.-]"); //$NON-NLS-1$

      if (tokens != null && tokens.length > 1 && tokens[position] != null) {
        version = Integer.parseInt(tokens[position]);
      }
    } catch (Exception e) {
      version = -1;
    }
    return version;
  }

  /**
   * The function iterates through the list of cookies in the cookiestore and tries to
   * match them with the cookieName. If there is a match, the cookieStore already
   * has a valid cookie and the client need not send Credentials for validation purpose.
   * @param cookieStore The cookie Store
   * @param cookieName Name of the cookie which needs to be validated
   * @param isSSL Whether this is a http/https connection
   * @return true or false based on whether the client needs to send the credentials or
   * not to the server.
   */
  static boolean needToSendCredentials(CookieStore cookieStore, String cookieName, boolean isSSL) {
    if (cookieName == null || cookieStore == null) {
      return true;
    }

    List cookies = cookieStore.getCookies();

    for (Cookie c : cookies) {
      // If this is a secured cookie and the current connection is non-secured,
      // then, skip this cookie. We need to skip this cookie because, the cookie
      // replay will not be transmitted to the server.
      if (c.isSecure() && !isSSL) {
        continue;
      }
      if (c.getName().equals(cookieName)) {
        return false;
      }
    }
    return true;
  }

  public static String parsePropertyFromUrl(final String url, final String key) {
    String[] tokens = url.split(";");
    for (String token : tokens) {
      if (token.trim().startsWith(key.trim() + "=")) {
        return token.trim().substring((key.trim() + "=").length());
      }
    }
    return null;
  }

  /**
   * Method to get canonical-ized hostname, given a hostname (possibly a CNAME).
   * This should allow for service-principals to use simplified CNAMEs.
   * @param hostName The hostname to be canonical-ized.
   * @return Given a CNAME, the canonical-ized hostname is returned. If not found, the original hostname is returned.
   */
  public static String getCanonicalHostName(String hostName) {
    try {
      return InetAddress.getByName(hostName).getCanonicalHostName();
    }
    catch(UnknownHostException exception) {
      LOG.warn("Could not retrieve canonical hostname for " + hostName, exception);
      return hostName;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy