/** Pings live connections. */
  public synchronized void doPing() throws SQLException {
    SQLException se = null;
    boolean foundHost = false;
    int pingTimeout = this.currentConnection.getLoadBalancePingTimeout();

    for (Iterator<String> i = this.hostList.iterator(); i.hasNext(); ) {
      String host = i.next();
      ConnectionImpl conn = this.liveConnections.get(host);
      if (conn == null) {
        continue;
      }
      try {
        if (pingTimeout == 0) {
          conn.ping();
        } else {
          conn.pingInternal(true, pingTimeout);
        }
        foundHost = true;
      } catch (SQLException e) {
        this.activePhysicalConnections--;
        // give up if it is the current connection, otherwise NPE faking resultset later.
        if (host.equals(this.connectionsToHostsMap.get(this.currentConnection))) {
          // clean up underlying connections, since connection pool won't do it
          closeAllConnections();
          this.isClosed = true;
          this.closedReason = "Connection closed because ping of current connection failed.";
          throw e;
        }

        // if the Exception is caused by ping connection lifetime checks, don't add to blacklist
        if (e.getMessage().equals(Messages.getString("Connection.exceededConnectionLifetime"))) {
          // only set the return Exception if it's null
          if (se == null) {
            se = e;
          }
        } else {
          // overwrite the return Exception no matter what
          se = e;
          if (isGlobalBlacklistEnabled()) {
            addToGlobalBlacklist(host);
          }
        }
        // take the connection out of the liveConnections Map
        this.liveConnections.remove(this.connectionsToHostsMap.get(conn));
      }
    }

    // if there were no successful pings
    if (!foundHost) {
      closeAllConnections();
      this.isClosed = true;
      this.closedReason = "Connection closed due to inability to ping any active connections.";
      // throw the stored Exception, if exists
      if (se != null) {
        throw se;
      }
      // or create a new SQLException and throw it, must be no liveConnections
      ((ConnectionImpl) this.currentConnection).throwConnectionClosedException();
    }
  }
  /**
   * Picks the "best" connection to use for the next transaction based on the BalanceStrategy in
   * use.
   *
   * @throws SQLException
   */
  @Override
  synchronized void pickNewConnection() throws SQLException {
    if (this.isClosed && this.closedExplicitly) {
      return;
    }

    if (this.currentConnection == null) { // startup
      this.currentConnection =
          this.balancer.pickConnection(
              this,
              Collections.unmodifiableList(this.hostList),
              Collections.unmodifiableMap(this.liveConnections),
              this.responseTimes.clone(),
              this.retriesAllDown);
      return;
    }

    if (this.currentConnection.isClosed()) {
      invalidateCurrentConnection();
    }

    int pingTimeout = this.currentConnection.getLoadBalancePingTimeout();
    boolean pingBeforeReturn =
        this.currentConnection.getLoadBalanceValidateConnectionOnSwapServer();

    for (int hostsTried = 0, hostsToTry = this.hostList.size();
        hostsTried < hostsToTry;
        hostsTried++) {
      ConnectionImpl newConn = null;
      try {
        newConn =
            this.balancer.pickConnection(
                this,
                Collections.unmodifiableList(this.hostList),
                Collections.unmodifiableMap(this.liveConnections),
                this.responseTimes.clone(),
                this.retriesAllDown);

        if (this.currentConnection != null) {
          if (pingBeforeReturn) {
            if (pingTimeout == 0) {
              newConn.ping();
            } else {
              newConn.pingInternal(true, pingTimeout);
            }
          }

          syncSessionState(this.currentConnection, newConn);
        }

        this.currentConnection = newConn;
        return;

      } catch (SQLException e) {
        if (shouldExceptionTriggerConnectionSwitch(e) && newConn != null) {
          // connection error, close up shop on current connection
          invalidateConnection(newConn);
        }
      }
    }

    // no hosts available to swap connection to, close up.
    this.isClosed = true;
    this.closedReason =
        "Connection closed after inability to pick valid new connection during load-balance.";
  }