Skip to content

Commit

Permalink
separated FireboltEngineServer to 2 implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
alexradzin committed Oct 31, 2023
1 parent cc9a376 commit 12f2f66
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 188 deletions.
19 changes: 9 additions & 10 deletions src/main/java/com/firebolt/jdbc/connection/FireboltConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import com.firebolt.jdbc.metadata.FireboltSystemEngineDatabaseMetadata;
import com.firebolt.jdbc.service.FireboltAccountIdService;
import com.firebolt.jdbc.service.FireboltAuthenticationService;
import com.firebolt.jdbc.service.FireboltEngineService;
import com.firebolt.jdbc.service.FireboltEngineInformationSchemaService;
import com.firebolt.jdbc.service.FireboltGatewayUrlService;
import com.firebolt.jdbc.service.FireboltStatementService;
import com.firebolt.jdbc.statement.FireboltStatement;
Expand Down Expand Up @@ -80,12 +80,12 @@ protected FireboltConnection(@NonNull String url, Properties connectionSettings,
FireboltAuthenticationService fireboltAuthenticationService,
FireboltGatewayUrlService fireboltGatewayUrlService,
FireboltStatementService fireboltStatementService,
FireboltEngineService fireboltEngineService,
FireboltEngineInformationSchemaService fireboltEngineService,
FireboltAccountIdService fireboltAccountIdService) throws SQLException {
this.loginProperties = extractFireboltProperties(url, connectionSettings);

this.fireboltAuthenticationService = fireboltAuthenticationService;
this.httpConnectionUrl = getHttpConnectionUrl(loginProperties);
this.httpConnectionUrl = loginProperties.getHttpConnectionUrl();
this.fireboltStatementService = fireboltStatementService;

this.statements = new ArrayList<>();
Expand All @@ -101,7 +101,7 @@ protected FireboltConnection(@NonNull String url, Properties connectionSettings)
ObjectMapper objectMapper = FireboltObjectMapper.getInstance();

this.fireboltAuthenticationService = new FireboltAuthenticationService(createFireboltAuthenticationClient(httpClient, objectMapper));
this.httpConnectionUrl = getHttpConnectionUrl(loginProperties);
this.httpConnectionUrl = loginProperties.getHttpConnectionUrl();
this.fireboltStatementService = new FireboltStatementService(new StatementClientImpl(httpClient, objectMapper, this, loginProperties.getUserDrivers(), loginProperties.getUserClients()));

this.statements = new ArrayList<>();
Expand All @@ -112,6 +112,10 @@ protected FireboltConnection(@NonNull String url, Properties connectionSettings)
protected abstract FireboltAuthenticationClient createFireboltAuthenticationClient(OkHttpClient httpClient, ObjectMapper objectMapper);

public static FireboltConnection create(@NonNull String url, Properties connectionSettings) throws SQLException {
return createConnectionInstance(url, connectionSettings);
}

private static FireboltConnection createConnectionInstance(@NonNull String url, Properties connectionSettings) throws SQLException {
switch(getUrlVersion(url)) {
case 1: return new FireboltConnectionUserPasswordAuthentication(url, connectionSettings);
case 2: return new FireboltConnectionServiceSecretAuthentication(url, connectionSettings);
Expand Down Expand Up @@ -312,16 +316,11 @@ public void close() {
log.debug("Connection closed");
}

protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) {
protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) throws SQLException {
Properties propertiesFromUrl = UrlUtil.extractProperties(jdbcUri);
return FireboltProperties.of(propertiesFromUrl, connectionProperties);
}

private String getHttpConnectionUrl(FireboltProperties newSessionProperties) {
String hostAndPort = newSessionProperties.getHost() + ":" + newSessionProperties.getPort();
return newSessionProperties.isSsl() ? "https://" + hostAndPort : "http://" + hostAndPort;
}

@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.firebolt.jdbc.exception.FireboltException;
import com.firebolt.jdbc.service.FireboltAccountIdService;
import com.firebolt.jdbc.service.FireboltAuthenticationService;
import com.firebolt.jdbc.service.FireboltEngineInformationSchemaService;
import com.firebolt.jdbc.service.FireboltEngineService;
import com.firebolt.jdbc.service.FireboltGatewayUrlService;
import com.firebolt.jdbc.service.FireboltStatementService;
Expand All @@ -31,7 +32,7 @@ public class FireboltConnectionServiceSecretAuthentication extends FireboltConne
private final FireboltAccountIdService fireboltAccountIdService;
private final FireboltEngineService fireboltEngineService;

FireboltConnectionServiceSecretAuthentication(@NonNull String url, Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltGatewayUrlService fireboltGatewayUrlService, FireboltStatementService fireboltStatementService, FireboltEngineService fireboltEngineService, FireboltAccountIdService fireboltAccountIdService) throws SQLException {
FireboltConnectionServiceSecretAuthentication(@NonNull String url, Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltGatewayUrlService fireboltGatewayUrlService, FireboltStatementService fireboltStatementService, FireboltEngineInformationSchemaService fireboltEngineService, FireboltAccountIdService fireboltAccountIdService) throws SQLException {
super(url, connectionSettings, fireboltAuthenticationService, fireboltGatewayUrlService, fireboltStatementService, fireboltEngineService, fireboltAccountIdService);
this.fireboltGatewayUrlService = fireboltGatewayUrlService;
this.fireboltAccountIdService = fireboltAccountIdService;
Expand All @@ -45,7 +46,7 @@ public class FireboltConnectionServiceSecretAuthentication extends FireboltConne
ObjectMapper objectMapper = FireboltObjectMapper.getInstance();
this.fireboltGatewayUrlService = new FireboltGatewayUrlService(createFireboltAccountRetriever(httpClient, objectMapper, "engineUrl", GatewayUrlResponse.class));
this.fireboltAccountIdService = new FireboltAccountIdService(createFireboltAccountRetriever(httpClient, objectMapper, "resolve", FireboltAccount.class));
this.fireboltEngineService = new FireboltEngineService(this, new FireboltAccountClient(httpClient, objectMapper, this, loginProperties.getUserDrivers(), loginProperties.getUserClients()));
this.fireboltEngineService = new FireboltEngineInformationSchemaService(this);
connect();
}

Expand All @@ -70,7 +71,7 @@ protected void authenticate() throws SQLException {

private FireboltProperties getSessionPropertiesForNonSystemEngine() throws SQLException {
sessionProperties = sessionProperties.toBuilder().engine(loginProperties.getEngine()).build();
Engine engine = fireboltEngineService.getEngine(loginProperties.getEngine(), loginProperties.getDatabase());
Engine engine = fireboltEngineService.getEngine(loginProperties);
return loginProperties.toBuilder().host(engine.getEndpoint()).engine(engine.getName()).systemEngine(false).database(engine.getDatabase()).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.firebolt.jdbc.connection.settings.FireboltProperties;
import com.firebolt.jdbc.service.FireboltAccountIdService;
import com.firebolt.jdbc.service.FireboltAuthenticationService;
import com.firebolt.jdbc.service.FireboltEngineApiService;
import com.firebolt.jdbc.service.FireboltEngineInformationSchemaService;
import com.firebolt.jdbc.service.FireboltEngineService;
import com.firebolt.jdbc.service.FireboltGatewayUrlService;
import com.firebolt.jdbc.service.FireboltStatementService;
Expand All @@ -23,7 +25,7 @@
public class FireboltConnectionUserPasswordAuthentication extends FireboltConnection {
private final FireboltEngineService fireboltEngineService;

FireboltConnectionUserPasswordAuthentication(@NonNull String url, Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltGatewayUrlService fireboltGatewayUrlService, FireboltStatementService fireboltStatementService, FireboltEngineService fireboltEngineService, FireboltAccountIdService fireboltAccountIdService) throws SQLException {
FireboltConnectionUserPasswordAuthentication(@NonNull String url, Properties connectionSettings, FireboltAuthenticationService fireboltAuthenticationService, FireboltGatewayUrlService fireboltGatewayUrlService, FireboltStatementService fireboltStatementService, FireboltEngineInformationSchemaService fireboltEngineService, FireboltAccountIdService fireboltAccountIdService) throws SQLException {
super(url, connectionSettings, fireboltAuthenticationService, fireboltGatewayUrlService, fireboltStatementService, fireboltEngineService, fireboltAccountIdService);
this.fireboltEngineService = fireboltEngineService;
connect();
Expand All @@ -33,19 +35,20 @@ public class FireboltConnectionUserPasswordAuthentication extends FireboltConnec
super(url, connectionSettings);
OkHttpClient httpClient = getHttpClient(loginProperties);
ObjectMapper objectMapper = FireboltObjectMapper.getInstance();
this.fireboltEngineService = new FireboltEngineService(this, new FireboltAccountClient(httpClient, objectMapper, this, loginProperties.getUserDrivers(), loginProperties.getUserClients()));
this.fireboltEngineService = new FireboltEngineApiService(new FireboltAccountClient(httpClient, objectMapper, this, loginProperties.getUserDrivers(), loginProperties.getUserClients()));
connect();
}

@Override
protected void authenticate() throws SQLException {
String accessToken = getAccessToken(loginProperties).orElse(StringUtils.EMPTY);
String endpoint = fireboltEngineService.getEngine(httpConnectionUrl, loginProperties, accessToken).getEndpoint();
FireboltProperties propertiesWithAccessToken = loginProperties.toBuilder().accessToken(accessToken).build();
String endpoint = fireboltEngineService.getEngine(propertiesWithAccessToken).getEndpoint();
this.sessionProperties = loginProperties.toBuilder().host(endpoint).build();
}

@Override
protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) {
protected FireboltProperties extractFireboltProperties(String jdbcUri, Properties connectionProperties) throws SQLException {
FireboltProperties properties = super.extractFireboltProperties(jdbcUri, connectionProperties);
boolean systemEngine = "system".equals(properties.getEngine());
return properties.toBuilder().systemEngine(systemEngine).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,10 @@ public void addProperty(@NonNull String key, String value) {
public void addProperty(Pair<String, String> property) {
this.addProperty(property.getLeft(), property.getRight());
}

public String getHttpConnectionUrl() {
String hostAndPort = getHost() + ":" + getPort();
return isSsl() ? "https://" + hostAndPort : "http://" + hostAndPort;
}

}
109 changes: 109 additions & 0 deletions src/main/java/com/firebolt/jdbc/service/FireboltEngineApiService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.firebolt.jdbc.service;

import com.firebolt.jdbc.client.account.FireboltAccountClient;
import com.firebolt.jdbc.client.account.response.FireboltAccountResponse;
import com.firebolt.jdbc.client.account.response.FireboltDefaultDatabaseEngineResponse;
import com.firebolt.jdbc.client.account.response.FireboltEngineIdResponse;
import com.firebolt.jdbc.client.account.response.FireboltEngineResponse;
import com.firebolt.jdbc.connection.Engine;
import com.firebolt.jdbc.connection.settings.FireboltProperties;
import com.firebolt.jdbc.exception.FireboltException;
import lombok.CustomLog;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Set;

@RequiredArgsConstructor
@CustomLog
public class FireboltEngineApiService implements FireboltEngineService {
private static final Set<String> ENGINE_NOT_READY_STATUSES = Set.of(
"ENGINE_STATUS_PROVISIONING_STARTED", "ENGINE_STATUS_PROVISIONING_PENDING",
"ENGINE_STATUS_PROVISIONING_FINISHED", "ENGINE_STATUS_RUNNING_REVISION_STARTING");
private static final String ERROR_NO_ENGINE_ATTACHED = "There is no Firebolt engine running on %s attached to the database %s. To connect first make sure there is a running engine and then try again.";
private static final String ERROR_NO_ENGINE_WITH_NAME = "There is no Firebolt engine running on %s with the name %s. To connect first make sure there is a running engine and then try again.";


private final FireboltAccountClient fireboltAccountClient;

@Override
public Engine getEngine(FireboltProperties properties) throws SQLException {
return getEngine(properties.getHttpConnectionUrl(), properties, properties.getAccessToken());
}

/**
* Returns the engine
*
* @param connectionUrl the connection url
* @param loginProperties properties to login
* @param accessToken the access token
* @return the engine
*/
private Engine getEngine(String connectionUrl, FireboltProperties loginProperties, String accessToken)
throws FireboltException {
String accountId = null;
Engine engine;
try {
if (StringUtils.isNotEmpty(loginProperties.getAccount())) {
accountId = getAccountId(connectionUrl, loginProperties.getAccount(), accessToken).orElse(null);
}
if (StringUtils.isEmpty(loginProperties.getEngine())) {
engine = getDefaultEngine(connectionUrl, accountId, loginProperties.getDatabase(), accessToken);
} else {
engine = getEngineWithName(connectionUrl, accountId, loginProperties.getEngine(), accessToken);
}
} catch (FireboltException e) {
throw e;
} catch (Exception e) {
throw new FireboltException("Failed to get engine", e);
}
validateEngineIsNotStarting(engine);
return engine;
}

private Engine getEngineWithName(String connectionUrl, String accountId, String engineName, String accessToken)
throws FireboltException, IOException {
FireboltEngineIdResponse response = fireboltAccountClient.getEngineId(connectionUrl, accountId, engineName,
accessToken);
String engineID = Optional.ofNullable(response).map(FireboltEngineIdResponse::getEngine)
.map(FireboltEngineIdResponse.Engine::getEngineId).orElseThrow(() -> new FireboltException(
"Failed to extract engine id field from the server response: the response from the server is invalid."));
FireboltEngineResponse fireboltEngineResponse = fireboltAccountClient.getEngine(connectionUrl, accountId,
engineName, engineID, accessToken);

return Optional.ofNullable(fireboltEngineResponse).map(FireboltEngineResponse::getEngine)
.filter(e -> StringUtils.isNotEmpty(e.getEndpoint()))
.map(e -> new Engine(e.getEndpoint(), e.getCurrentStatus(), engineName, null, engineID))
.orElseThrow(() -> new FireboltException(
String.format(ERROR_NO_ENGINE_WITH_NAME, connectionUrl, engineName)));
}

private Engine getDefaultEngine(String connectionUrl, String accountId, String database, String accessToken)
throws FireboltException, IOException {
FireboltDefaultDatabaseEngineResponse defaultEngine = fireboltAccountClient
.getDefaultEngineByDatabaseName(connectionUrl, accountId, database, accessToken);

return Optional.ofNullable(defaultEngine).map(FireboltDefaultDatabaseEngineResponse::getEngineUrl)
.map(url -> new Engine(url, "running", null, database, null)).orElseThrow(
() -> new FireboltException(String.format(ERROR_NO_ENGINE_ATTACHED, connectionUrl, database)));
}

private Optional<String> getAccountId(String connectionUrl, String account, String accessToken)
throws FireboltException, IOException {
FireboltAccountResponse fireboltAccountResponse = fireboltAccountClient.getAccount(connectionUrl, account,
accessToken);
return Optional.ofNullable(fireboltAccountResponse).map(FireboltAccountResponse::getAccountId);
}

private void validateEngineIsNotStarting(Engine engine) throws FireboltException {
if (StringUtils.isNotEmpty(engine.getId()) && StringUtils.isNotEmpty(engine.getStatus())
&& ENGINE_NOT_READY_STATUSES.contains(engine.getStatus())) {
throw new FireboltException(String.format(
"The engine %s is currently starting. Please wait until the engine is on and then execute the query again.", engine.getName()));
}
}

}
Loading

0 comments on commit 12f2f66

Please sign in to comment.