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

io.trino.jdbc.$internal.client.uri.TrinoUri Maven / Gradle / Ivy

There is a newer version: 458
Show newest version
/*
 * Licensed 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 io.trino.jdbc.\$internal.client.uri;

import io.trino.jdbc.\$internal.guava.annotations.VisibleForTesting;
import io.trino.jdbc.\$internal.guava.base.Splitter;
import io.trino.jdbc.\$internal.guava.collect.ImmutableMap;
import io.trino.jdbc.\$internal.guava.net.HostAndPort;
import io.trino.jdbc.\$internal.client.ClientException;
import io.trino.jdbc.\$internal.client.ClientSelectedRole;
import io.trino.jdbc.\$internal.client.DnsResolver;
import io.trino.jdbc.\$internal.client.OkHttpUtil;
import io.trino.jdbc.\$internal.client.auth.external.CompositeRedirectHandler;
import io.trino.jdbc.\$internal.client.auth.external.ExternalAuthenticator;
import io.trino.jdbc.\$internal.client.auth.external.ExternalRedirectStrategy;
import io.trino.jdbc.\$internal.client.auth.external.HttpTokenPoller;
import io.trino.jdbc.\$internal.client.auth.external.RedirectHandler;
import io.trino.jdbc.\$internal.client.auth.external.TokenPoller;
import io.trino.jdbc.\$internal.okhttp3.OkHttpClient;
import org.ietf.jgss.GSSCredential;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.time.Duration;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static io.trino.jdbc.\$internal.guava.base.MoreObjects.firstNonNull;
import static io.trino.jdbc.\$internal.guava.base.Strings.isNullOrEmpty;
import static io.trino.jdbc.\$internal.guava.collect.ImmutableMap.toImmutableMap;
import static io.trino.jdbc.\$internal.client.KerberosUtil.defaultCredentialCachePath;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.basicAuth;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.disableHttp2;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupAlternateHostnameVerification;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupCookieJar;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupHttpProxy;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupInsecureSsl;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupKerberos;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupSocksProxy;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.setupSsl;
import static io.trino.jdbc.\$internal.client.OkHttpUtil.tokenAuth;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.ACCESS_TOKEN;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.APPLICATION_NAME_PREFIX;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.ASSUME_LITERAL_NAMES_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.ASSUME_LITERAL_UNDERSCORE_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.CLIENT_INFO;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.CLIENT_TAGS;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.DISABLE_COMPRESSION;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.DNS_RESOLVER;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.DNS_RESOLVER_CONTEXT;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXPLICIT_PREPARE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXTERNAL_AUTHENTICATION;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXTERNAL_AUTHENTICATION_REDIRECT_HANDLERS;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXTERNAL_AUTHENTICATION_TIMEOUT;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXTERNAL_AUTHENTICATION_TOKEN_CACHE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.EXTRA_CREDENTIALS;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.HOSTNAME_IN_CERTIFICATE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.HTTP_PROXY;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_CONFIG_PATH;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_CONSTRAINED_DELEGATION;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_CREDENTIAL_CACHE_PATH;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_DELEGATION;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_KEYTAB_PATH;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_PRINCIPAL;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_REMOTE_SERVICE_NAME;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_SERVICE_PRINCIPAL_PATTERN;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.KERBEROS_USE_CANONICAL_HOSTNAME;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.PASSWORD;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.ROLES;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SESSION_PROPERTIES;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SESSION_USER;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SOCKS_PROXY;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SOURCE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_KEY_STORE_PASSWORD;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_KEY_STORE_PATH;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_KEY_STORE_TYPE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_TRUST_STORE_PASSWORD;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_TRUST_STORE_PATH;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_TRUST_STORE_TYPE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_USE_SYSTEM_TRUST_STORE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SSL_VERIFICATION;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SslVerificationMode;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SslVerificationMode.CA;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SslVerificationMode.FULL;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.SslVerificationMode.NONE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.TIMEZONE;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.TRACE_TOKEN;
import static io.trino.jdbc.\$internal.client.uri.ConnectionProperties.USER;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
 * Parses and extracts parameters from a Trino URL.
 */
public class TrinoUri
{
    private static final String URL_START = "trino:";

    private static final Splitter QUERY_SPLITTER = Splitter.on('&').omitEmptyStrings();
    private static final Splitter ARG_SPLITTER = Splitter.on('=').limit(2);
    private static final AtomicReference REDIRECT_HANDLER = new AtomicReference<>(null);
    private final HostAndPort address;
    private final URI uri;

    private final Properties properties;

    private Optional user;
    private Optional password;
    private Optional sessionUser;
    private Optional> roles;
    private Optional socksProxy;
    private Optional httpProxy;
    private Optional applicationNamePrefix;
    private Optional disableCompression;
    private Optional assumeLiteralNamesInMetadataCallsForNonConformingClients;
    private Optional assumeLiteralUnderscoreInMetadataCallsForNonConformingClients;
    private Optional ssl;
    private Optional sslVerification;
    private Optional sslKeyStorePath;
    private Optional sslKeyStorePassword;
    private Optional sslKeyStoreType;
    private Optional sslTrustStorePath;
    private Optional sslTrustStorePassword;
    private Optional sslTrustStoreType;
    private Optional sslUseSystemTrustStore;
    private Optional kerberosServicePrincipalPattern;
    private Optional kerberosRemoteServiceName;
    private Optional kerberosUseCanonicalHostname;
    private Optional kerberosPrincipal;
    private Optional kerberosConfigPath;
    private Optional kerberosKeytabPath;
    private Optional kerberosCredentialCachePath;
    private Optional kerberosDelegation;
    private Optional kerberosConstrainedDelegation;
    private Optional accessToken;
    private Optional externalAuthentication;
    private Optional externalAuthenticationTimeout;
    private Optional> externalRedirectStrategies;
    private Optional externalAuthenticationTokenCache;
    private Optional> extraCredentials;
    private Optional hostnameInCertificate;
    private Optional timeZone;
    private Optional clientInfo;
    private Optional clientTags;
    private Optional traceToken;
    private Optional> sessionProperties;
    private Optional source;
    private Optional explicitPrepare;

    private Optional catalog = Optional.empty();
    private Optional schema = Optional.empty();
    private final List restrictedProperties;

    private final boolean useSecureConnection;

    private TrinoUri(
            URI uri,
            Optional catalog,
            Optional schema,
            List restrictedProperties,
            Optional user,
            Optional password,
            Optional sessionUser,
            Optional> roles,
            Optional socksProxy,
            Optional httpProxy,
            Optional applicationNamePrefix,
            Optional disableCompression,
            Optional assumeLiteralNamesInMetadataCallsForNonConformingClients,
            Optional assumeLiteralUnderscoreInMetadataCallsForNonConformingClients,
            Optional ssl,
            Optional sslVerification,
            Optional sslKeyStorePath,
            Optional sslKeyStorePassword,
            Optional sslKeyStoreType,
            Optional sslTrustStorePath,
            Optional sslTrustStorePassword,
            Optional sslTrustStoreType,
            Optional sslUseSystemTrustStore,
            Optional kerberosServicePrincipalPattern,
            Optional kerberosRemoteServiceName,
            Optional kerberosUseCanonicalHostname,
            Optional kerberosPrincipal,
            Optional kerberosConfigPath,
            Optional kerberosKeytabPath,
            Optional kerberosCredentialCachePath,
            Optional kerberosDelegation,
            Optional kerberosConstrainedDelegation,
            Optional accessToken,
            Optional externalAuthentication,
            Optional externalAuthenticationTimeout,
            Optional> externalRedirectStrategies,
            Optional externalAuthenticationTokenCache,
            Optional> extraCredentials,
            Optional hostnameInCertificate,
            Optional timeZone,
            Optional clientInfo,
            Optional clientTags,
            Optional traceToken,
            Optional> sessionProperties,
            Optional source,
            Optional explicitPrepare)
            throws SQLException
    {
        this.uri = requireNonNull(uri, "uri is null");
        this.catalog = catalog;
        this.schema = schema;
        this.restrictedProperties = restrictedProperties;

        Map urlParameters = parseParameters(uri.getQuery());
        Properties urlProperties = new Properties();
        urlProperties.putAll(urlParameters);

        this.user = USER.getValueOrDefault(urlProperties, user);
        this.password = PASSWORD.getValueOrDefault(urlProperties, password);
        this.sessionUser = SESSION_USER.getValueOrDefault(urlProperties, sessionUser);
        this.roles = ROLES.getValueOrDefault(urlProperties, roles);
        this.socksProxy = SOCKS_PROXY.getValueOrDefault(urlProperties, socksProxy);
        this.httpProxy = HTTP_PROXY.getValueOrDefault(urlProperties, httpProxy);
        this.applicationNamePrefix = APPLICATION_NAME_PREFIX.getValueOrDefault(urlProperties, applicationNamePrefix);
        this.disableCompression = DISABLE_COMPRESSION.getValueOrDefault(urlProperties, disableCompression);
        this.assumeLiteralNamesInMetadataCallsForNonConformingClients = ASSUME_LITERAL_NAMES_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.getValueOrDefault(urlProperties, assumeLiteralNamesInMetadataCallsForNonConformingClients);
        this.assumeLiteralUnderscoreInMetadataCallsForNonConformingClients = ASSUME_LITERAL_UNDERSCORE_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.getValueOrDefault(urlProperties, assumeLiteralUnderscoreInMetadataCallsForNonConformingClients);
        this.ssl = SSL.getValueOrDefault(urlProperties, ssl);
        this.sslVerification = SSL_VERIFICATION.getValueOrDefault(urlProperties, sslVerification);
        this.sslKeyStorePath = SSL_KEY_STORE_PATH.getValueOrDefault(urlProperties, sslKeyStorePath);
        this.sslKeyStorePassword = SSL_KEY_STORE_PASSWORD.getValueOrDefault(urlProperties, sslKeyStorePassword);
        this.sslKeyStoreType = SSL_KEY_STORE_TYPE.getValueOrDefault(urlProperties, sslKeyStoreType);
        this.sslTrustStorePath = SSL_TRUST_STORE_PATH.getValueOrDefault(urlProperties, sslTrustStorePath);
        this.sslTrustStorePassword = SSL_TRUST_STORE_PASSWORD.getValueOrDefault(urlProperties, sslTrustStorePassword);
        this.sslTrustStoreType = SSL_TRUST_STORE_TYPE.getValueOrDefault(urlProperties, sslTrustStoreType);
        this.sslUseSystemTrustStore = SSL_USE_SYSTEM_TRUST_STORE.getValueOrDefault(urlProperties, sslUseSystemTrustStore);
        this.kerberosServicePrincipalPattern = KERBEROS_SERVICE_PRINCIPAL_PATTERN.getValueOrDefault(urlProperties, kerberosServicePrincipalPattern);
        this.kerberosRemoteServiceName = KERBEROS_REMOTE_SERVICE_NAME.getValueOrDefault(urlProperties, kerberosRemoteServiceName);
        this.kerberosUseCanonicalHostname = KERBEROS_USE_CANONICAL_HOSTNAME.getValueOrDefault(urlProperties, kerberosUseCanonicalHostname);
        this.kerberosPrincipal = KERBEROS_PRINCIPAL.getValueOrDefault(urlProperties, kerberosPrincipal);
        this.kerberosConfigPath = KERBEROS_CONFIG_PATH.getValueOrDefault(urlProperties, kerberosConfigPath);
        this.kerberosKeytabPath = KERBEROS_KEYTAB_PATH.getValueOrDefault(urlProperties, kerberosKeytabPath);
        this.kerberosCredentialCachePath = KERBEROS_CREDENTIAL_CACHE_PATH.getValueOrDefault(urlProperties, kerberosCredentialCachePath);
        this.kerberosDelegation = KERBEROS_DELEGATION.getValueOrDefault(urlProperties, kerberosDelegation);
        this.kerberosConstrainedDelegation = KERBEROS_CONSTRAINED_DELEGATION.getValueOrDefault(urlProperties, kerberosConstrainedDelegation);
        this.accessToken = ACCESS_TOKEN.getValueOrDefault(urlProperties, accessToken);
        this.externalAuthentication = EXTERNAL_AUTHENTICATION.getValueOrDefault(urlProperties, externalAuthentication);
        this.externalAuthenticationTimeout = EXTERNAL_AUTHENTICATION_TIMEOUT.getValueOrDefault(urlProperties, externalAuthenticationTimeout);
        this.externalRedirectStrategies = EXTERNAL_AUTHENTICATION_REDIRECT_HANDLERS.getValueOrDefault(urlProperties, externalRedirectStrategies);
        this.externalAuthenticationTokenCache = EXTERNAL_AUTHENTICATION_TOKEN_CACHE.getValueOrDefault(urlProperties, externalAuthenticationTokenCache);
        this.extraCredentials = EXTRA_CREDENTIALS.getValueOrDefault(urlProperties, extraCredentials);
        this.hostnameInCertificate = HOSTNAME_IN_CERTIFICATE.getValueOrDefault(urlProperties, hostnameInCertificate);
        this.timeZone = TIMEZONE.getValueOrDefault(urlProperties, timeZone);
        this.clientInfo = CLIENT_INFO.getValueOrDefault(urlProperties, clientInfo);
        this.clientTags = CLIENT_TAGS.getValueOrDefault(urlProperties, clientTags);
        this.traceToken = TRACE_TOKEN.getValueOrDefault(urlProperties, traceToken);
        this.sessionProperties = SESSION_PROPERTIES.getValueOrDefault(urlProperties, sessionProperties);
        this.source = SOURCE.getValueOrDefault(urlProperties, source);
        this.explicitPrepare = EXPLICIT_PREPARE.getValueOrDefault(urlProperties, explicitPrepare);

        properties = buildProperties();

        // enable SSL by default for the trino schema and the standard port
        useSecureConnection = SSL.getValue(properties).orElse(uri.getScheme().equals("https") || (uri.getScheme().equals("trino") && uri.getPort() == 443));
        if (!password.orElse("").isEmpty()) {
            if (!useSecureConnection) {
                throw new SQLException("TLS/SSL required for authentication with username and password");
            }
        }
        validateConnectionProperties(properties);

        this.address = HostAndPort.fromParts(uri.getHost(), uri.getPort() == -1 ? (useSecureConnection ? 443 : 80) : uri.getPort());
        initCatalogAndSchema();
    }

    private Properties buildProperties()
    {
        Properties properties = new Properties();
        user.ifPresent(value -> properties.setProperty(PropertyName.USER.toString(), value));
        password.ifPresent(value -> properties.setProperty(PropertyName.PASSWORD.toString(), value));
        sessionUser.ifPresent(value -> properties.setProperty(PropertyName.SESSION_USER.toString(), value));
        roles.ifPresent(value -> properties.setProperty(
                PropertyName.ROLES.toString(),
                value.entrySet().stream()
                        .map(entry -> entry.getKey() + ":" + entry.getValue())
                        .collect(Collectors.joining(";"))));
        socksProxy.ifPresent(value -> properties.setProperty(PropertyName.SOCKS_PROXY.toString(), value.toString()));
        httpProxy.ifPresent(value -> properties.setProperty(PropertyName.HTTP_PROXY.toString(), value.toString()));
        applicationNamePrefix.ifPresent(value -> properties.setProperty(PropertyName.APPLICATION_NAME_PREFIX.toString(), value));
        disableCompression.ifPresent(value -> properties.setProperty(PropertyName.DISABLE_COMPRESSION.toString(), Boolean.toString(value)));
        assumeLiteralNamesInMetadataCallsForNonConformingClients.ifPresent(
                value -> properties.setProperty(
                        PropertyName.ASSUME_LITERAL_NAMES_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.toString(),
                        Boolean.toString(value)));
        assumeLiteralUnderscoreInMetadataCallsForNonConformingClients.ifPresent(
                value -> properties.setProperty(
                        PropertyName.ASSUME_LITERAL_UNDERSCORE_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.toString(),
                        Boolean.toString(value)));
        ssl.ifPresent(value -> properties.setProperty(PropertyName.SSL.toString(), Boolean.toString(value)));
        sslVerification.ifPresent(value -> properties.setProperty(PropertyName.SSL_VERIFICATION.toString(), value.toString()));
        sslKeyStoreType.ifPresent(value -> properties.setProperty(PropertyName.SSL_KEY_STORE_TYPE.toString(), value));
        sslKeyStorePath.ifPresent(value -> properties.setProperty(PropertyName.SSL_KEY_STORE_PATH.toString(), value));
        sslKeyStorePassword.ifPresent(value -> properties.setProperty(PropertyName.SSL_KEY_STORE_PASSWORD.toString(), value));
        sslTrustStoreType.ifPresent(value -> properties.setProperty(PropertyName.SSL_TRUST_STORE_TYPE.toString(), value));
        sslTrustStorePath.ifPresent(value -> properties.setProperty(PropertyName.SSL_TRUST_STORE_PATH.toString(), value));
        sslTrustStorePassword.ifPresent(value -> properties.setProperty(PropertyName.SSL_TRUST_STORE_PASSWORD.toString(), value));
        sslUseSystemTrustStore.ifPresent(value -> properties.setProperty(PropertyName.SSL_USE_SYSTEM_TRUST_STORE.toString(), Boolean.toString(value)));
        kerberosServicePrincipalPattern.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_SERVICE_PRINCIPAL_PATTERN.toString(), value));
        kerberosRemoteServiceName.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_REMOTE_SERVICE_NAME.toString(), value));
        kerberosUseCanonicalHostname.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_USE_CANONICAL_HOSTNAME.toString(), Boolean.toString(value)));
        kerberosPrincipal.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_PRINCIPAL.toString(), value));
        kerberosConfigPath.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_CONFIG_PATH.toString(), value.getPath()));
        kerberosKeytabPath.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_KEYTAB_PATH.toString(), value.getPath()));
        kerberosCredentialCachePath.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_CREDENTIAL_CACHE_PATH.toString(), value.getPath()));
        kerberosDelegation.ifPresent(value -> properties.setProperty(PropertyName.KERBEROS_DELEGATION.toString(), Boolean.toString(value)));
        kerberosConstrainedDelegation.ifPresent(value -> properties.put(PropertyName.KERBEROS_CONSTRAINED_DELEGATION.toString(), value));
        accessToken.ifPresent(value -> properties.setProperty(PropertyName.ACCESS_TOKEN.toString(), value));
        externalAuthentication.ifPresent(value -> properties.setProperty(PropertyName.EXTERNAL_AUTHENTICATION.toString(), Boolean.toString(value)));
        externalAuthenticationTimeout.ifPresent(value -> properties.setProperty(PropertyName.EXTERNAL_AUTHENTICATION_TIMEOUT.toString(), value.toString()));
        externalRedirectStrategies.ifPresent(value ->
                properties.setProperty(
                        PropertyName.EXTERNAL_AUTHENTICATION_REDIRECT_HANDLERS.toString(),
                        value.stream()
                                .map(ExternalRedirectStrategy::toString)
                                .collect(Collectors.joining(","))));
        externalAuthenticationTokenCache.ifPresent(value -> properties.setProperty(PropertyName.EXTERNAL_AUTHENTICATION_TOKEN_CACHE.toString(), value.toString()));
        extraCredentials.ifPresent(value ->
                properties.setProperty(
                        PropertyName.EXTRA_CREDENTIALS.toString(),
                        value.entrySet().stream()
                                .map(entry -> entry.getKey() + ":" + entry.getValue())
                                .collect(Collectors.joining(";"))));
        sessionProperties.ifPresent(value ->
                properties.setProperty(
                        PropertyName.SESSION_PROPERTIES.toString(),
                        value.entrySet().stream()
                                .map(entry -> entry.getKey() + ":" + entry.getValue())
                                .collect(Collectors.joining(";"))));
        hostnameInCertificate.ifPresent(value -> properties.setProperty(PropertyName.HOSTNAME_IN_CERTIFICATE.toString(), value));
        timeZone.ifPresent(value -> properties.setProperty(PropertyName.TIMEZONE.toString(), value.getId()));
        clientInfo.ifPresent(value -> properties.setProperty(PropertyName.CLIENT_INFO.toString(), value));
        clientTags.ifPresent(value -> properties.setProperty(PropertyName.CLIENT_TAGS.toString(), value));
        traceToken.ifPresent(value -> properties.setProperty(PropertyName.TRACE_TOKEN.toString(), value));
        source.ifPresent(value -> properties.setProperty(PropertyName.SOURCE.toString(), value));
        explicitPrepare.ifPresent(value -> properties.setProperty(PropertyName.EXPLICIT_PREPARE.toString(), value.toString()));
        return properties;
    }

    protected TrinoUri(String url, Properties properties)
            throws SQLException
    {
        this(parseDriverUrl(url), properties);
    }

    protected TrinoUri(URI uri, Properties driverProperties)
            throws SQLException
    {
        this.restrictedProperties = Collections.emptyList();
        this.uri = requireNonNull(uri, "uri is null");
        properties = mergeConnectionProperties(uri, driverProperties);

        validateConnectionProperties(properties);

        this.user = USER.getValue(properties);
        this.password = PASSWORD.getValue(properties);
        this.sessionUser = SESSION_USER.getValue(properties);
        this.roles = ROLES.getValue(properties);
        this.socksProxy = SOCKS_PROXY.getValue(properties);
        this.httpProxy = HTTP_PROXY.getValue(properties);
        this.applicationNamePrefix = APPLICATION_NAME_PREFIX.getValue(properties);
        this.disableCompression = DISABLE_COMPRESSION.getValue(properties);
        this.assumeLiteralNamesInMetadataCallsForNonConformingClients = ASSUME_LITERAL_NAMES_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.getValue(properties);
        this.assumeLiteralUnderscoreInMetadataCallsForNonConformingClients = ASSUME_LITERAL_UNDERSCORE_IN_METADATA_CALLS_FOR_NON_CONFORMING_CLIENTS.getValue(properties);
        this.ssl = SSL.getValue(properties);
        this.sslVerification = SSL_VERIFICATION.getValue(properties);
        this.sslKeyStorePath = SSL_KEY_STORE_PATH.getValue(properties);
        this.sslKeyStorePassword = SSL_KEY_STORE_PASSWORD.getValue(properties);
        this.sslKeyStoreType = SSL_KEY_STORE_TYPE.getValue(properties);
        this.sslTrustStorePath = SSL_TRUST_STORE_PATH.getValue(properties);
        this.sslTrustStorePassword = SSL_TRUST_STORE_PASSWORD.getValue(properties);
        this.sslTrustStoreType = SSL_TRUST_STORE_TYPE.getValue(properties);
        this.sslUseSystemTrustStore = SSL_USE_SYSTEM_TRUST_STORE.getValue(properties);
        this.kerberosServicePrincipalPattern = KERBEROS_SERVICE_PRINCIPAL_PATTERN.getValue(properties);
        this.kerberosRemoteServiceName = KERBEROS_REMOTE_SERVICE_NAME.getValue(properties);
        this.kerberosUseCanonicalHostname = KERBEROS_USE_CANONICAL_HOSTNAME.getValue(properties);
        this.kerberosPrincipal = KERBEROS_PRINCIPAL.getValue(properties);
        this.kerberosConfigPath = KERBEROS_CONFIG_PATH.getValue(properties);
        this.kerberosKeytabPath = KERBEROS_KEYTAB_PATH.getValue(properties);
        this.kerberosCredentialCachePath = KERBEROS_CREDENTIAL_CACHE_PATH.getValue(properties);
        this.kerberosDelegation = KERBEROS_DELEGATION.getValue(properties);
        this.kerberosConstrainedDelegation = KERBEROS_CONSTRAINED_DELEGATION.getValue(properties);
        this.accessToken = ACCESS_TOKEN.getValue(properties);
        this.externalAuthentication = EXTERNAL_AUTHENTICATION.getValue(properties);
        this.externalAuthenticationTimeout = EXTERNAL_AUTHENTICATION_TIMEOUT.getValue(properties);
        this.externalRedirectStrategies = EXTERNAL_AUTHENTICATION_REDIRECT_HANDLERS.getValue(properties);
        this.externalAuthenticationTokenCache = EXTERNAL_AUTHENTICATION_TOKEN_CACHE.getValue(properties);
        this.extraCredentials = EXTRA_CREDENTIALS.getValue(properties);
        this.hostnameInCertificate = HOSTNAME_IN_CERTIFICATE.getValue(properties);
        this.timeZone = TIMEZONE.getValue(properties);
        this.clientInfo = CLIENT_INFO.getValue(properties);
        this.clientTags = CLIENT_TAGS.getValue(properties);
        this.traceToken = TRACE_TOKEN.getValue(properties);
        this.sessionProperties = SESSION_PROPERTIES.getValue(properties);
        this.source = SOURCE.getValue(properties);
        this.explicitPrepare = EXPLICIT_PREPARE.getValue(properties);

        // enable SSL by default for the trino schema and the standard port
        useSecureConnection = ssl.orElse(uri.getScheme().equals("https") || (uri.getScheme().equals("trino") && uri.getPort() == 443));
        address = HostAndPort.fromParts(uri.getHost(), uri.getPort() == -1 ? (useSecureConnection ? 443 : 80) : uri.getPort());

        initCatalogAndSchema();
    }

    public static TrinoUri create(String url, Properties properties)
            throws SQLException
    {
        return new TrinoUri(url, firstNonNull(properties, new Properties()));
    }

    public static TrinoUri create(URI uri, Properties properties)
            throws SQLException
    {
        return new TrinoUri(uri, firstNonNull(properties, new Properties()));
    }

    public URI getUri()
    {
        return uri;
    }

    public Optional getSchema()
    {
        return schema;
    }

    public Optional getCatalog()
    {
        return catalog;
    }

    public URI getHttpUri()
    {
        return buildHttpUri();
    }

    public String getRequiredUser()
            throws SQLException
    {
        return checkRequired(user, PropertyName.USER);
    }

    public static  T checkRequired(Optional obj, PropertyName name)
            throws SQLException
    {
        return obj.orElseThrow(() -> new SQLException(format("Connection property '%s' is required", name)));
    }

    public Optional getUser()
    {
        return user;
    }

    public boolean hasPassword()
    {
        return password.isPresent();
    }

    public Optional getSessionUser()
    {
        return sessionUser;
    }

    public Map getRoles()
    {
        return roles.orElse(ImmutableMap.of());
    }

    public Optional getApplicationNamePrefix()
    {
        return applicationNamePrefix;
    }

    public Map getExtraCredentials()
    {
        return extraCredentials.orElse(ImmutableMap.of());
    }

    public Optional getClientInfo()
    {
        return clientInfo;
    }

    public Optional getClientTags()
    {
        return clientTags;
    }

    public Optional getTraceToken()
    {
        return traceToken;
    }

    public Map getSessionProperties()
    {
        return sessionProperties.orElse(ImmutableMap.of());
    }

    public Optional getSource()
    {
        return source;
    }

    public Optional getExplicitPrepare()
    {
        return explicitPrepare;
    }

    public boolean isCompressionDisabled()
    {
        return disableCompression.orElse(false);
    }

    public boolean isAssumeLiteralNamesInMetadataCallsForNonConformingClients()
    {
        return assumeLiteralNamesInMetadataCallsForNonConformingClients.orElse(false);
    }

    public boolean isAssumeLiteralUnderscoreInMetadataCallsForNonConformingClients()
    {
        return assumeLiteralUnderscoreInMetadataCallsForNonConformingClients.orElse(false);
    }

    public ZoneId getTimeZone()
    {
        return timeZone.orElseGet(ZoneId::systemDefault);
    }

    public Properties getProperties()
    {
        return properties;
    }

    public static DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
    {
        Properties properties = urlProperties(url, info);

        return ConnectionProperties.allProperties().stream()
                .filter(property -> property.isValid(properties))
                .map(property -> property.getDriverPropertyInfo(properties))
                .toArray(DriverPropertyInfo[]::new);
    }

    private static Properties urlProperties(String url, Properties info)
    {
        try {
            return create(url, info).getProperties();
        }
        catch (SQLException e) {
            return info;
        }
    }

    public Consumer getSetupSsl()
    {
        if (!useSecureConnection) {
            return OkHttpUtil::setupInsecureSsl;
        }
        SslVerificationMode sslVerificationMode = sslVerification.orElse(FULL);
        if (sslVerificationMode.equals(NONE)) {
            return OkHttpUtil::setupInsecureSsl;
        }
        return builder -> setupSsl(
                builder,
                sslKeyStorePath,
                sslKeyStorePassword,
                sslKeyStoreType,
                sslTrustStorePath,
                sslTrustStorePassword,
                sslTrustStoreType,
                sslUseSystemTrustStore.orElse(false));
    }

    public void setupClient(OkHttpClient.Builder builder)
            throws SQLException
    {
        try {
            disableHttp2(builder);
            setupCookieJar(builder);
            setupSocksProxy(builder, socksProxy);
            setupHttpProxy(builder, httpProxy);

            String password = this.password.orElse("");
            if (!password.isEmpty()) {
                if (!useSecureConnection) {
                    throw new SQLException("TLS/SSL is required for authentication with username and password");
                }
                builder.addInterceptor(basicAuth(getRequiredUser(), password));
            }

            if (useSecureConnection) {
                SslVerificationMode sslVerificationMode = sslVerification.orElse(FULL);
                if (sslVerificationMode.equals(FULL) || sslVerificationMode.equals(CA)) {
                    setupSsl(
                            builder,
                            sslKeyStorePath,
                            sslKeyStorePassword,
                            sslKeyStoreType,
                            sslTrustStorePath,
                            sslTrustStorePassword,
                            sslTrustStoreType,
                            sslUseSystemTrustStore.orElse(false));
                }
                if (sslVerificationMode.equals(FULL)) {
                    HOSTNAME_IN_CERTIFICATE.getValue(properties).ifPresent(certHostname ->
                            setupAlternateHostnameVerification(builder, certHostname));
                }

                if (sslVerificationMode.equals(CA)) {
                    builder.hostnameVerifier((hostname, session) -> true);
                }

                if (sslVerificationMode.equals(NONE)) {
                    setupInsecureSsl(builder);
                }
            }

            if (kerberosRemoteServiceName.isPresent()) {
                if (!useSecureConnection) {
                    throw new SQLException("TLS/SSL is required for Kerberos authentication");
                }
                setupKerberos(
                        builder,
                        checkRequired(kerberosServicePrincipalPattern, PropertyName.KERBEROS_SERVICE_PRINCIPAL_PATTERN),
                        checkRequired(kerberosRemoteServiceName, PropertyName.KERBEROS_REMOTE_SERVICE_NAME),
                        checkRequired(kerberosUseCanonicalHostname, PropertyName.KERBEROS_USE_CANONICAL_HOSTNAME),
                        kerberosPrincipal,
                        kerberosConfigPath,
                        kerberosKeytabPath,
                        Optional.ofNullable(kerberosCredentialCachePath
                                .orElseGet(() -> defaultCredentialCachePath().map(File::new).orElse(null))),
                        kerberosDelegation.orElse(false),
                        kerberosConstrainedDelegation);
            }

            if (accessToken.isPresent()) {
                if (!useSecureConnection) {
                    throw new SQLException("TLS/SSL required for authentication using an access token");
                }
                builder.addNetworkInterceptor(tokenAuth(accessToken.get()));
            }

            if (externalAuthentication.orElse(false)) {
                if (!useSecureConnection) {
                    throw new SQLException("TLS/SSL required for authentication using external authorization");
                }

                // create HTTP client that shares the same settings, but without the external authenticator
                TokenPoller poller = new HttpTokenPoller(builder.build());

                Duration timeout = externalAuthenticationTimeout
                        .map(value -> Duration.ofMillis(value.toMillis()))
                        .orElse(Duration.ofMinutes(2));

                KnownTokenCache knownTokenCache = externalAuthenticationTokenCache.orElse(KnownTokenCache.NONE);

                Optional configuredHandler = externalRedirectStrategies
                        .map(CompositeRedirectHandler::new)
                        .map(RedirectHandler.class::cast);

                RedirectHandler redirectHandler = Optional.ofNullable(REDIRECT_HANDLER.get())
                        .orElseGet(() -> configuredHandler.orElseThrow(() -> new RuntimeException("External authentication redirect handler is not configured")));

                ExternalAuthenticator authenticator = new ExternalAuthenticator(
                        redirectHandler, poller, knownTokenCache.create(), timeout);

                builder.authenticator(authenticator);
                builder.addNetworkInterceptor(authenticator);
            }

            Optional resolverContext = DNS_RESOLVER_CONTEXT.getValue(properties);
            DNS_RESOLVER.getValue(properties).ifPresent(resolverClass -> builder.dns(instantiateDnsResolver(resolverClass, resolverContext)::lookup));
        }
        catch (ClientException e) {
            throw new SQLException(e.getMessage(), e);
        }
        catch (RuntimeException e) {
            throw new SQLException("Error setting up connection", e);
        }
    }

    private static DnsResolver instantiateDnsResolver(Class resolverClass, Optional context)
    {
        try {
            return resolverClass.getConstructor(String.class).newInstance(context.orElse(null));
        }
        catch (ReflectiveOperationException e) {
            throw new ClientException("Unable to instantiate custom DNS resolver " + resolverClass.getName(), e);
        }
    }

    private Map parseParameters(String query)
            throws SQLException
    {
        Map result = new HashMap<>();

        if (query == null) {
            return result;
        }

        Iterable queryArgs = QUERY_SPLITTER.split(query);
        for (String queryArg : queryArgs) {
            List parts = ARG_SPLITTER.splitToList(queryArg);
            if (parts.size() != 2) {
                throw new SQLException(format("Connection argument is not a valid connection property: '%s'", queryArg));
            }

            String key = parts.get(0);
            PropertyName name = PropertyName.findByKey(key).orElseThrow(() -> new SQLException(format("Unrecognized connection property '%s'", key)));
            if (restrictedProperties.contains(name)) {
                throw new RestrictedPropertyException(name, format("Connection property %s cannot be set in the URL", parts.get(0)));
            }
            if (result.put(parts.get(0), parts.get(1)) != null) {
                throw new SQLException(format("Connection property %s is in the URL multiple times", parts.get(0)));
            }
        }

        return result;
    }

    private static URI parseDriverUrl(String url)
            throws SQLException
    {
        validatePrefix(url);
        URI uri = parseUrl(url);

        if (isNullOrEmpty(uri.getHost())) {
            throw new SQLException("No host specified: " + url);
        }
        if (uri.getPort() == -1) {
            throw new SQLException("No port number specified: " + url);
        }
        if ((uri.getPort() < 1) || (uri.getPort() > 65535)) {
            throw new SQLException("Invalid port number: " + url);
        }
        return uri;
    }

    private static URI parseUrl(String url)
            throws SQLException
    {
        try {
            return new URI(url);
        }
        catch (URISyntaxException e) {
            throw new SQLException("Invalid Trino URL: " + url, e);
        }
    }

    private static void validatePrefix(String url)
            throws SQLException
    {
        if (!url.startsWith(URL_START)) {
            throw new SQLException("Invalid Trino URL: " + url);
        }

        if (url.equals(URL_START)) {
            throw new SQLException("Empty Trino URL: " + url);
        }
    }

    private URI buildHttpUri()
    {
        String scheme = useSecureConnection ? "https" : "http";
        try {
            return new URI(scheme, null, address.getHost(), address.getPort(), null, null, null);
        }
        catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    private void initCatalogAndSchema()
            throws SQLException
    {
        String path = uri.getPath();
        if (isNullOrEmpty(uri.getPath()) || path.equals("/")) {
            return;
        }

        // remove first slash
        if (!path.startsWith("/")) {
            throw new SQLException("Path does not start with a slash: " + uri);
        }
        path = path.substring(1);

        List parts = Splitter.on("/").splitToList(path);
        // remove last item due to a trailing slash
        if (parts.get(parts.size() - 1).isEmpty()) {
            parts = parts.subList(0, parts.size() - 1);
        }

        if (parts.size() > 2) {
            throw new SQLException("Invalid path segments in URL: " + uri);
        }

        if (parts.get(0).isEmpty()) {
            throw new SQLException("Catalog name is empty: " + uri);
        }

        if (catalog.isPresent()) {
            throw new RestrictedPropertyException(PropertyName.CATALOG, "Catalog cannot be set in the URL");
        }
        catalog = Optional.ofNullable(parts.get(0));

        if (parts.size() > 1) {
            if (parts.get(1).isEmpty()) {
                throw new SQLException("Schema name is empty: " + uri);
            }

            if (schema.isPresent()) {
                throw new RestrictedPropertyException(PropertyName.SCHEMA, "Schema cannot be set in the URL");
            }
            schema = Optional.ofNullable(parts.get(1));
        }
    }

    private Properties mergeConnectionProperties(URI uri, Properties driverProperties)
            throws SQLException
    {
        Map urlProperties = parseParameters(uri.getQuery());
        Map suppliedProperties = driverProperties.entrySet().stream()
                .collect(toImmutableMap(entry -> (String) entry.getKey(), Entry::getValue));

        for (String key : urlProperties.keySet()) {
            if (suppliedProperties.containsKey(key)) {
                throw new SQLException(format("Connection property %s is both in the URL and an argument", key));
            }
        }

        Properties result = new Properties();
        setProperties(result, suppliedProperties);
        setProperties(result, urlProperties);
        return result;
    }

    private static void setProperties(Properties properties, Map values)
    {
        properties.putAll(values);
    }

    private static void validateConnectionProperties(Properties connectionProperties)
            throws SQLException
    {
        for (String propertyName : connectionProperties.stringPropertyNames()) {
            if (ConnectionProperties.forKey(propertyName) == null) {
                throw new SQLException(format("Unrecognized connection property '%s'", propertyName));
            }
        }

        for (ConnectionProperty property : ConnectionProperties.allProperties()) {
            property.validate(connectionProperties);
        }
    }

    @VisibleForTesting
    public static void setRedirectHandler(RedirectHandler handler)
    {
        REDIRECT_HANDLER.set(requireNonNull(handler, "handler is null"));
    }

    public static Builder builder()
    {
        return new Builder();
    }

    public static final class Builder
    {
        private URI uri;
        private String catalog;
        private String schema;
        private List restrictedProperties;
        private String user;
        private String password;
        private String sessionUser;
        private Map roles;
        private HostAndPort socksProxy;
        private HostAndPort httpProxy;
        private String applicationNamePrefix;
        private Boolean disableCompression;
        private Boolean assumeLiteralNamesInMetadataCallsForNonConformingClients;
        private Boolean assumeLiteralUnderscoreInMetadataCallsForNonConformingClients;
        private Boolean ssl;
        private SslVerificationMode sslVerification;
        private String sslKeyStorePath;
        private String sslKeyStorePassword;
        private String sslKeyStoreType;
        private String sslTrustStorePath;
        private String sslTrustStorePassword;
        private String sslTrustStoreType;
        private Boolean sslUseSystemTrustStore;
        private String kerberosServicePrincipalPattern;
        private String kerberosRemoteServiceName;
        private Boolean kerberosUseCanonicalHostname;
        private String kerberosPrincipal;
        private File kerberosConfigPath;
        private File kerberosKeytabPath;
        private File kerberosCredentialCachePath;
        private Boolean kerberosDelegation;
        private GSSCredential kerberosConstrainedDelegation;
        private String accessToken;
        private Boolean externalAuthentication;
        private io.trino.jdbc.\$internal.airlift.units.Duration externalAuthenticationTimeout;
        private List externalRedirectStrategies;
        private KnownTokenCache externalAuthenticationTokenCache;
        private Map extraCredentials;
        private String hostnameInCertificate;
        private ZoneId timeZone;
        private String clientInfo;
        private String clientTags;
        private String traceToken;
        private Map sessionProperties;
        private String source;
        private Boolean explicitPrepare;

        private Builder() {}

        public Builder setUri(URI uri)
        {
            this.uri = requireNonNull(uri, "uri is null");
            return this;
        }

        public Builder setCatalog(String catalog)
        {
            this.catalog = requireNonNull(catalog, "catalog is null");
            return this;
        }

        public Builder setSchema(String schema)
        {
            this.schema = requireNonNull(schema, "schema is null");
            return this;
        }

        public Builder setRestrictedProperties(List restrictedProperties)
        {
            this.restrictedProperties = requireNonNull(restrictedProperties, "restrictedProperties is null");
            return this;
        }

        public Builder setUser(String user)
        {
            this.user = requireNonNull(user, "user is null");
            return this;
        }

        public Builder setPassword(String password)
        {
            this.password = requireNonNull(password, "password is null");
            return this;
        }

        public Builder setSessionUser(String sessionUser)
        {
            this.sessionUser = requireNonNull(sessionUser, "sessionUser is null");
            return this;
        }

        public Builder setRoles(Map roles)
        {
            this.roles = requireNonNull(roles, "roles is null");
            return this;
        }

        public Builder setSocksProxy(HostAndPort socksProxy)
        {
            this.socksProxy = requireNonNull(socksProxy, "socksProxy is null");
            return this;
        }

        public Builder setHttpProxy(HostAndPort httpProxy)
        {
            this.httpProxy = requireNonNull(httpProxy, "httpProxy is null");
            return this;
        }

        public Builder setApplicationNamePrefix(String applicationNamePrefix)
        {
            this.applicationNamePrefix = requireNonNull(applicationNamePrefix, "applicationNamePrefix is null");
            return this;
        }

        public Builder setDisableCompression(Boolean disableCompression)
        {
            this.disableCompression = requireNonNull(disableCompression, "disableCompression is null");
            return this;
        }

        public Builder setAssumeLiteralNamesInMetadataCallsForNonConformingClients(Boolean assumeLiteralNamesInMetadataCallsForNonConformingClients)
        {
            this.assumeLiteralNamesInMetadataCallsForNonConformingClients = requireNonNull(assumeLiteralNamesInMetadataCallsForNonConformingClients, "assumeLiteralNamesInMetadataCallsForNonConformingClients is null");
            return this;
        }

        public Builder setAssumeLiteralUnderscoreInMetadataCallsForNonConformingClients(Boolean assumeLiteralUnderscoreInMetadataCallsForNonConformingClients)
        {
            this.assumeLiteralUnderscoreInMetadataCallsForNonConformingClients = requireNonNull(assumeLiteralUnderscoreInMetadataCallsForNonConformingClients, "assumeLiteralUnderscoreInMetadataCallsForNonConformingClients is null");
            return this;
        }

        public Builder setSsl(Boolean ssl)
        {
            this.ssl = requireNonNull(ssl, "ssl is null");
            return this;
        }

        public Builder setSslVerificationNone()
        {
            this.sslVerification = NONE;
            return this;
        }

        public Builder setSslKeyStorePath(String sslKeyStorePath)
        {
            this.sslKeyStorePath = requireNonNull(sslKeyStorePath, "sslKeyStorePath is null");
            return this;
        }

        public Builder setSslKeyStorePassword(String sslKeyStorePassword)
        {
            this.sslKeyStorePassword = requireNonNull(sslKeyStorePassword, "sslKeyStorePassword is null");
            return this;
        }

        public Builder setSslKeyStoreType(String sslKeyStoreType)
        {
            this.sslKeyStoreType = requireNonNull(sslKeyStoreType, "sslKeyStoreType is null");
            return this;
        }

        public Builder setSslTrustStorePath(String sslTrustStorePath)
        {
            this.sslTrustStorePath = requireNonNull(sslTrustStorePath, "sslTrustStorePath is null");
            return this;
        }

        public Builder setSslTrustStorePassword(String sslTrustStorePassword)
        {
            this.sslTrustStorePassword = requireNonNull(sslTrustStorePassword, "sslTrustStorePassword is null");
            return this;
        }

        public Builder setSslTrustStoreType(String sslTrustStoreType)
        {
            this.sslTrustStoreType = requireNonNull(sslTrustStoreType, "sslTrustStoreType is null");
            return this;
        }

        public Builder setSslUseSystemTrustStore(Boolean sslUseSystemTrustStore)
        {
            this.sslUseSystemTrustStore = requireNonNull(sslUseSystemTrustStore, "sslUseSystemTrustStore is null");
            return this;
        }

        public Builder setKerberosServicePrincipalPattern(String kerberosServicePrincipalPattern)
        {
            this.kerberosServicePrincipalPattern = requireNonNull(kerberosServicePrincipalPattern, "kerberosServicePrincipalPattern is null");
            return this;
        }

        public Builder setKerberosRemoveServiceName(String kerberosRemoteServiceName)
        {
            this.kerberosRemoteServiceName = requireNonNull(kerberosRemoteServiceName, "kerberosRemoteServiceName is null");
            return this;
        }

        public Builder setKerberosUseCanonicalHostname(Boolean kerberosUseCanonicalHostname)
        {
            this.kerberosUseCanonicalHostname = requireNonNull(kerberosUseCanonicalHostname, "kerberosUseCanonicalHostname is null");
            return this;
        }

        public Builder setKerberosPrincipal(String kerberosPrincipal)
        {
            this.kerberosPrincipal = requireNonNull(kerberosPrincipal, "kerberosPrincipal is null");
            return this;
        }

        public Builder setKerberosConfigPath(String kerberosConfigPath)
        {
            return setKerberosConfigPath(new File(requireNonNull(kerberosConfigPath, "kerberosConfigPath is null")));
        }

        public Builder setKerberosConfigPath(File kerberosConfigPath)
        {
            this.kerberosConfigPath = requireNonNull(kerberosConfigPath, "kerberosConfigPath is null");
            return this;
        }

        public Builder setKerberosKeytabPath(String kerberosKeytabPath)
        {
            return setKerberosKeytabPath(new File(requireNonNull(kerberosKeytabPath, "kerberosKeytabPath is null")));
        }

        public Builder setKerberosKeytabPath(File kerberosKeytabPath)
        {
            this.kerberosKeytabPath = requireNonNull(kerberosKeytabPath, "kerberosKeytabPath is null");
            return this;
        }

        public Builder setKerberosCredentialCachePath(String kerberosCredentialCachePath)
        {
            return setKerberosCredentialCachePath(new File(requireNonNull(kerberosCredentialCachePath, "kerberosCredentialCachePath is null")));
        }

        public Builder setKerberosCredentialCachePath(File kerberosCredentialCachePath)
        {
            this.kerberosCredentialCachePath = requireNonNull(kerberosCredentialCachePath, "kerberosCredentialCachePath is null");
            return this;
        }

        public Builder setKerberosDelegation(Boolean kerberosDelegation)
        {
            this.kerberosDelegation = requireNonNull(kerberosDelegation, "kerberosDelegation is null");
            return this;
        }

        public Builder setKerberosConstrainedDelegation(GSSCredential kerberosConstrainedDelegation)
        {
            this.kerberosConstrainedDelegation = requireNonNull(kerberosConstrainedDelegation, "kerberosConstrainedDelegation is null");
            return this;
        }

        public Builder setAccessToken(String accessToken)
        {
            this.accessToken = requireNonNull(accessToken, "accessToken is null");
            return this;
        }

        public Builder setExternalAuthentication(Boolean externalAuthentication)
        {
            this.externalAuthentication = requireNonNull(externalAuthentication, "externalAuthentication is null");
            return this;
        }

        public Builder setExternalAuthenticationTimeout(io.trino.jdbc.\$internal.airlift.units.Duration externalAuthenticationTimeout)
        {
            this.externalAuthenticationTimeout = requireNonNull(externalAuthenticationTimeout, "externalAuthenticationTimeout is null");
            return this;
        }

        public Builder setExternalRedirectStrategies(List externalRedirectStrategies)
        {
            this.externalRedirectStrategies = requireNonNull(externalRedirectStrategies, "externalRedirectStrategies is null");
            return this;
        }

        public Builder setExternalAuthenticationTokenCache(KnownTokenCache externalAuthenticationTokenCache)
        {
            this.externalAuthenticationTokenCache = requireNonNull(externalAuthenticationTokenCache, "externalAuthenticationTokenCache is null");
            return this;
        }

        public Builder setExtraCredentials(Map extraCredentials)
        {
            this.extraCredentials = requireNonNull(extraCredentials, "extraCredentials is null");
            return this;
        }

        public Builder setHostnameInCertificate(String hostnameInCertificate)
        {
            this.hostnameInCertificate = requireNonNull(hostnameInCertificate, "hostnameInCertificate is null");
            return this;
        }

        public Builder setTimeZone(ZoneId timeZone)
        {
            this.timeZone = requireNonNull(timeZone, "timeZone is null");
            return this;
        }

        public Builder setClientInfo(String clientInfo)
        {
            this.clientInfo = requireNonNull(clientInfo, "clientInfo is null");
            return this;
        }

        public Builder setClientTags(String clientTags)
        {
            this.clientTags = requireNonNull(clientTags, "clientTags is null");
            return this;
        }

        public Builder setTraceToken(String traceToken)
        {
            this.traceToken = requireNonNull(traceToken, "traceToken is null");
            return this;
        }

        public Builder setSessionProperties(Map sessionProperties)
        {
            this.sessionProperties = requireNonNull(sessionProperties, "sessionProperties is null");
            return this;
        }

        public Builder setSource(String source)
        {
            this.source = requireNonNull(source, "source is null");
            return this;
        }

        public Builder setExplicitPrepare(Boolean explicitPrepare)
        {
            this.explicitPrepare = requireNonNull(explicitPrepare, "explicitPrepare is null");
            return this;
        }

        public TrinoUri build()
                throws SQLException
        {
            return new TrinoUri(
                    uri,
                    Optional.ofNullable(catalog),
                    Optional.ofNullable(schema),
                    restrictedProperties,
                    Optional.ofNullable(user),
                    Optional.ofNullable(password),
                    Optional.ofNullable(sessionUser),
                    Optional.ofNullable(roles),
                    Optional.ofNullable(socksProxy),
                    Optional.ofNullable(httpProxy),
                    Optional.ofNullable(applicationNamePrefix),
                    Optional.ofNullable(disableCompression),
                    Optional.ofNullable(assumeLiteralNamesInMetadataCallsForNonConformingClients),
                    Optional.ofNullable(assumeLiteralUnderscoreInMetadataCallsForNonConformingClients),
                    Optional.ofNullable(ssl),
                    Optional.ofNullable(sslVerification),
                    Optional.ofNullable(sslKeyStorePath),
                    Optional.ofNullable(sslKeyStorePassword),
                    Optional.ofNullable(sslKeyStoreType),
                    Optional.ofNullable(sslTrustStorePath),
                    Optional.ofNullable(sslTrustStorePassword),
                    Optional.ofNullable(sslTrustStoreType),
                    Optional.ofNullable(sslUseSystemTrustStore),
                    Optional.ofNullable(kerberosServicePrincipalPattern),
                    Optional.ofNullable(kerberosRemoteServiceName),
                    Optional.ofNullable(kerberosUseCanonicalHostname),
                    Optional.ofNullable(kerberosPrincipal),
                    Optional.ofNullable(kerberosConfigPath),
                    Optional.ofNullable(kerberosKeytabPath),
                    Optional.ofNullable(kerberosCredentialCachePath),
                    Optional.ofNullable(kerberosDelegation),
                    Optional.ofNullable(kerberosConstrainedDelegation),
                    Optional.ofNullable(accessToken),
                    Optional.ofNullable(externalAuthentication),
                    Optional.ofNullable(externalAuthenticationTimeout),
                    Optional.ofNullable(externalRedirectStrategies),
                    Optional.ofNullable(externalAuthenticationTokenCache),
                    Optional.ofNullable(extraCredentials),
                    Optional.ofNullable(hostnameInCertificate),
                    Optional.ofNullable(timeZone),
                    Optional.ofNullable(clientInfo),
                    Optional.ofNullable(clientTags),
                    Optional.ofNullable(traceToken),
                    Optional.ofNullable(sessionProperties),
                    Optional.ofNullable(source),
                    Optional.ofNullable(explicitPrepare));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy