public QueryExecutor openConnectionImpl()

in src/main/java/com/amazon/redshift/core/v3/ConnectionFactoryImpl.java [177:348]


  public QueryExecutor openConnectionImpl(HostSpec[] hostSpecs, String user, String database,
      Properties info, RedshiftLogger logger) throws SQLException {
    this.logger = logger;
  	SslMode sslMode = SslMode.of(info);

    HostRequirement targetServerType;
    String targetServerTypeStr = RedshiftProperty.TARGET_SERVER_TYPE.get(info);
    try {
      targetServerType = HostRequirement.getTargetServerType(targetServerTypeStr);
    } catch (IllegalArgumentException ex) {
      throw new RedshiftException(
          GT.tr("Invalid targetServerType value: {0}", targetServerTypeStr),
          RedshiftState.CONNECTION_UNABLE_TO_CONNECT);
    }

    SocketFactory socketFactory = SocketFactoryFactory.getSocketFactory(info);

    HostChooser hostChooser =
        HostChooserFactory.createHostChooser(hostSpecs, targetServerType, info);
    Iterator<CandidateHost> hostIter = hostChooser.iterator();
    Map<HostSpec, HostStatus> knownStates = new HashMap<HostSpec, HostStatus>();
    while (hostIter.hasNext()) {
      CandidateHost candidateHost = hostIter.next();
      HostSpec hostSpec = candidateHost.hostSpec;
    	if(RedshiftLogger.isEnable())
    		logger.log(LogLevel.DEBUG, "Trying to establish a protocol version 3 connection to {0}", hostSpec);

      // Note: per-connect-attempt status map is used here instead of GlobalHostStatusTracker
      // for the case when "no good hosts" match (e.g. all the hosts are known as "connectfail")
      // In that case, the system tries to connect to each host in order, thus it should not look into
      // GlobalHostStatusTracker
      HostStatus knownStatus = knownStates.get(hostSpec);
      if (knownStatus != null && !candidateHost.targetServerType.allowConnectingTo(knownStatus)) {
      	if(RedshiftLogger.isEnable()) {
          logger.log(LogLevel.DEBUG, "Known status of host {0} is {1}, and required status was {2}. Will try next host",
                     new Object[]{hostSpec, knownStatus, candidateHost.targetServerType});
        }
        continue;
      }

      //
      // Establish a connection.
      //

      RedshiftStream newStream = null;
      try {
        try {
          newStream = tryConnect(user, database, info, socketFactory, hostSpec, sslMode);
        } catch (SQLException e) {
          if (sslMode == SslMode.PREFER
              && RedshiftState.INVALID_AUTHORIZATION_SPECIFICATION.getState().equals(e.getSQLState())) {
            // Try non-SSL connection to cover case like "non-ssl only db"
            // Note: PREFER allows loss of encryption, so no significant harm is made
            Throwable ex = null;
            try {
              newStream =
                  tryConnect(user, database, info, socketFactory, hostSpec, SslMode.DISABLE);
            	if(RedshiftLogger.isEnable())
            		logger.log(LogLevel.DEBUG, "Downgraded to non-encrypted connection for host {0}",
                  hostSpec);
            } catch (SQLException ee) {
              ex = ee;
            } catch (IOException ee) {
              ex = ee; // Can't use multi-catch in Java 6 :(
            }
            if (ex != null) {
            	if(RedshiftLogger.isEnable())
            		logger.log(LogLevel.DEBUG, ex, "sslMode==PREFER, however non-SSL connection failed as well");
              // non-SSL failed as well, so re-throw original exception
              //JCP! if mvn.project.property.redshift.jdbc.spec >= "JDBC4.1"
              // Add non-SSL exception as suppressed
              e.addSuppressed(ex);
              //JCP! endif
              throw e;
            }
          } else if (sslMode == SslMode.ALLOW
              && RedshiftState.INVALID_AUTHORIZATION_SPECIFICATION.getState().equals(e.getSQLState())) {
            // Try using SSL
            Throwable ex = null;
            try {
              newStream =
                  tryConnect(user, database, info, socketFactory, hostSpec, SslMode.REQUIRE);
              if(RedshiftLogger.isEnable())
              	logger.log(LogLevel.DEBUG, "Upgraded to encrypted connection for host {0}",
              							hostSpec);
            } catch (SQLException ee) {
              ex = ee;
            } catch (IOException ee) {
              ex = ee; // Can't use multi-catch in Java 6 :(
            }
            if (ex != null) {
            	if(RedshiftLogger.isEnable())
            		logger.log(LogLevel.DEBUG, ex, "sslMode==ALLOW, however SSL connection failed as well");
              // non-SSL failed as well, so re-throw original exception
              //JCP! if mvn.project.property.redshift.jdbc.spec >= "JDBC4.1"
              // Add SSL exception as suppressed
              e.addSuppressed(ex);
              //JCP! endif
              throw e;
            }

          } else {
            throw e;
          }
        }

        int cancelSignalTimeout = RedshiftProperty.CANCEL_SIGNAL_TIMEOUT.getInt(info) * 1000;

        // Do final startup.
        QueryExecutor queryExecutor = new QueryExecutorImpl(newStream, user, database,
            cancelSignalTimeout, info, logger);

        // Check Primary or Secondary
        HostStatus hostStatus = HostStatus.ConnectOK;
        if (candidateHost.targetServerType != HostRequirement.any) {
          hostStatus = isPrimary(queryExecutor) ? HostStatus.Primary : HostStatus.Secondary;
        }
        GlobalHostStatusTracker.reportHostStatus(hostSpec, hostStatus);
        knownStates.put(hostSpec, hostStatus);
        if (!candidateHost.targetServerType.allowConnectingTo(hostStatus)) {
          queryExecutor.close();
          continue;
        }

        runInitialQueries(queryExecutor, info);

        // And we're done.
        return queryExecutor;
      } catch (ConnectException cex) {
        // Added by Peter Mount <peter@retep.org.uk>
        // ConnectException is thrown when the connection cannot be made.
        // we trap this an return a more meaningful message for the end user
        GlobalHostStatusTracker.reportHostStatus(hostSpec, HostStatus.ConnectFail);
        knownStates.put(hostSpec, HostStatus.ConnectFail);
        if (hostIter.hasNext()) {
        	if(RedshiftLogger.isEnable())
        		logger.log(LogLevel.DEBUG, cex, "ConnectException occurred while connecting to {0}", hostSpec);
          // still more addresses to try
          continue;
        }
        throw new RedshiftException(GT.tr(
            "Connection to {0} refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.",
            hostSpec), RedshiftState.CONNECTION_UNABLE_TO_CONNECT, cex);
      } catch (IOException ioe) {
        closeStream(newStream);
        GlobalHostStatusTracker.reportHostStatus(hostSpec, HostStatus.ConnectFail);
        knownStates.put(hostSpec, HostStatus.ConnectFail);
        if (hostIter.hasNext()) {
        	if(RedshiftLogger.isEnable())
        		logger.log(LogLevel.DEBUG, ioe, "IOException occurred while connecting to {0}", hostSpec);
          // still more addresses to try
          continue;
        }
        throw new RedshiftException(GT.tr("The connection attempt failed."),
            RedshiftState.CONNECTION_UNABLE_TO_CONNECT, ioe);
      } catch (SQLException se) {
        closeStream(newStream);
        GlobalHostStatusTracker.reportHostStatus(hostSpec, HostStatus.ConnectFail);
        knownStates.put(hostSpec, HostStatus.ConnectFail);
        if (hostIter.hasNext()) {
        	if(RedshiftLogger.isEnable())
        		logger.log(LogLevel.DEBUG, se, "SQLException occurred while connecting to {0}", hostSpec);
          // still more addresses to try
          continue;
        }
        throw se;
      }
    }
    throw new RedshiftException(GT
        .tr("Could not find a server with specified targetServerType: {0}", targetServerType),
        RedshiftState.CONNECTION_UNABLE_TO_CONNECT);
  }