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

io.prestosql.jdbc.ConnectionProperties Maven / Gradle / Ivy

There is a newer version: 350
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.prestosql.jdbc;

import io.prestosql.jdbc.$internal.guava.base.CharMatcher;
import io.prestosql.jdbc.$internal.guava.base.Splitter;
import io.prestosql.jdbc.$internal.guava.collect.ImmutableMap;
import io.prestosql.jdbc.$internal.guava.collect.ImmutableSet;
import io.prestosql.jdbc.$internal.guava.net.HostAndPort;
import io.prestosql.jdbc.$internal.client.ClientSelectedRole;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Predicate;

import static io.prestosql.jdbc.$internal.guava.base.Preconditions.checkArgument;
import static io.prestosql.jdbc.$internal.guava.collect.ImmutableMap.toImmutableMap;
import static io.prestosql.jdbc.$internal.guava.collect.Maps.immutableEntry;
import static io.prestosql.jdbc.$internal.client.ClientSelectedRole.Type.ALL;
import static io.prestosql.jdbc.$internal.client.ClientSelectedRole.Type.NONE;
import static io.prestosql.jdbc.AbstractConnectionProperty.checkedPredicate;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;

final class ConnectionProperties
{
    public static final ConnectionProperty USER = new User();
    public static final ConnectionProperty PASSWORD = new Password();
    public static final ConnectionProperty> ROLES = new Roles();
    public static final ConnectionProperty SOCKS_PROXY = new SocksProxy();
    public static final ConnectionProperty HTTP_PROXY = new HttpProxy();
    public static final ConnectionProperty APPLICATION_NAME_PREFIX = new ApplicationNamePrefix();
    public static final ConnectionProperty SSL = new Ssl();
    public static final ConnectionProperty SSL_KEY_STORE_PATH = new SslKeyStorePath();
    public static final ConnectionProperty SSL_KEY_STORE_PASSWORD = new SslKeyStorePassword();
    public static final ConnectionProperty SSL_KEY_STORE_TYPE = new SslKeyStoreType();
    public static final ConnectionProperty SSL_TRUST_STORE_PATH = new SslTrustStorePath();
    public static final ConnectionProperty SSL_TRUST_STORE_PASSWORD = new SslTrustStorePassword();
    public static final ConnectionProperty SSL_TRUST_STORE_TYPE = new SslTrustStoreType();
    public static final ConnectionProperty KERBEROS_SERVICE_PRINCIPAL_PATTERN = new KerberosServicePrincipalPattern();
    public static final ConnectionProperty KERBEROS_REMOTE_SERVICE_NAME = new KerberosRemoteServiceName();
    public static final ConnectionProperty KERBEROS_USE_CANONICAL_HOSTNAME = new KerberosUseCanonicalHostname();
    public static final ConnectionProperty KERBEROS_PRINCIPAL = new KerberosPrincipal();
    public static final ConnectionProperty KERBEROS_CONFIG_PATH = new KerberosConfigPath();
    public static final ConnectionProperty KERBEROS_KEYTAB_PATH = new KerberosKeytabPath();
    public static final ConnectionProperty KERBEROS_CREDENTIAL_CACHE_PATH = new KerberosCredentialCachePath();
    public static final ConnectionProperty ACCESS_TOKEN = new AccessToken();
    public static final ConnectionProperty> EXTRA_CREDENTIALS = new ExtraCredentials();
    public static final ConnectionProperty CLIENT_INFO = new ClientInfo();
    public static final ConnectionProperty CLIENT_TAGS = new ClientTags();
    public static final ConnectionProperty TRACE_TOKEN = new TraceToken();
    public static final ConnectionProperty USE_SESSION_TIMEZONE = new UseSessionTimeZone();
    public static final ConnectionProperty> SESSION_PROPERTIES = new SessionProperties();
    public static final ConnectionProperty SOURCE = new Source();

    private static final Set> ALL_PROPERTIES = ImmutableSet.>builder()
            .add(USER)
            .add(PASSWORD)
            .add(ROLES)
            .add(SOCKS_PROXY)
            .add(HTTP_PROXY)
            .add(APPLICATION_NAME_PREFIX)
            .add(SSL)
            .add(SSL_KEY_STORE_PATH)
            .add(SSL_KEY_STORE_PASSWORD)
            .add(SSL_KEY_STORE_TYPE)
            .add(SSL_TRUST_STORE_PATH)
            .add(SSL_TRUST_STORE_PASSWORD)
            .add(SSL_TRUST_STORE_TYPE)
            .add(KERBEROS_REMOTE_SERVICE_NAME)
            .add(KERBEROS_SERVICE_PRINCIPAL_PATTERN)
            .add(KERBEROS_USE_CANONICAL_HOSTNAME)
            .add(KERBEROS_PRINCIPAL)
            .add(KERBEROS_CONFIG_PATH)
            .add(KERBEROS_KEYTAB_PATH)
            .add(KERBEROS_CREDENTIAL_CACHE_PATH)
            .add(ACCESS_TOKEN)
            .add(EXTRA_CREDENTIALS)
            .add(CLIENT_INFO)
            .add(CLIENT_TAGS)
            .add(TRACE_TOKEN)
            .add(USE_SESSION_TIMEZONE)
            .add(SESSION_PROPERTIES)
            .add(SOURCE)
            .build();

    private static final Map> KEY_LOOKUP = unmodifiableMap(ALL_PROPERTIES.stream()
            .collect(toMap(ConnectionProperty::getKey, identity())));

    private static final Map DEFAULTS;

    static {
        ImmutableMap.Builder defaults = ImmutableMap.builder();
        for (ConnectionProperty property : ALL_PROPERTIES) {
            property.getDefault().ifPresent(value -> defaults.put(property.getKey(), value));
        }
        DEFAULTS = defaults.build();
    }

    private ConnectionProperties() {}

    public static ConnectionProperty forKey(String propertiesKey)
    {
        return KEY_LOOKUP.get(propertiesKey);
    }

    public static Set> allProperties()
    {
        return ALL_PROPERTIES;
    }

    public static Map getDefaults()
    {
        return DEFAULTS;
    }

    private static class User
            extends AbstractConnectionProperty
    {
        public User()
        {
            super("user", REQUIRED, ALLOWED, NON_EMPTY_STRING_CONVERTER);
        }
    }

    private static class Password
            extends AbstractConnectionProperty
    {
        public Password()
        {
            super("password", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class Roles
            extends AbstractConnectionProperty>
    {
        public Roles()
        {
            super("roles", NOT_REQUIRED, ALLOWED, Roles::parseRoles);
        }

        // Roles consists of a list of catalog role pairs.
        // E.g., `jdbc:presto://example.net:8080/?roles=catalog1:none;catalog2:all;catalog3:role` will set following roles:
        //  - `none` in `catalog1`
        //  - `all` in `catalog2`
        //  - `role` in `catalog3`
        public static Map parseRoles(String roles)
        {
            return new MapPropertyParser("roles").parse(roles).entrySet().stream()
                    .collect(toImmutableMap(Map.Entry::getKey, entry -> mapToClientSelectedRole(entry.getValue())));
        }

        private static ClientSelectedRole mapToClientSelectedRole(String role)
        {
            checkArgument(!role.contains("\""), "Role must not contain double quotes: %s", role);
            if (ALL.name().equalsIgnoreCase(role)) {
                return new ClientSelectedRole(ALL, Optional.empty());
            }
            if (NONE.name().equalsIgnoreCase(role)) {
                return new ClientSelectedRole(NONE, Optional.empty());
            }
            return new ClientSelectedRole(ClientSelectedRole.Type.ROLE, Optional.of(role));
        }
    }

    private static class SocksProxy
            extends AbstractConnectionProperty
    {
        private static final Predicate NO_HTTP_PROXY =
                checkedPredicate(properties -> !HTTP_PROXY.getValue(properties).isPresent());

        public SocksProxy()
        {
            super("socksProxy", NOT_REQUIRED, NO_HTTP_PROXY, HostAndPort::fromString);
        }
    }

    private static class HttpProxy
            extends AbstractConnectionProperty
    {
        private static final Predicate NO_SOCKS_PROXY =
                checkedPredicate(properties -> !SOCKS_PROXY.getValue(properties).isPresent());

        public HttpProxy()
        {
            super("httpProxy", NOT_REQUIRED, NO_SOCKS_PROXY, HostAndPort::fromString);
        }
    }

    private static class ApplicationNamePrefix
            extends AbstractConnectionProperty
    {
        public ApplicationNamePrefix()
        {
            super("applicationNamePrefix", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class ClientInfo
            extends AbstractConnectionProperty
    {
        public ClientInfo()
        {
            super("clientInfo", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class ClientTags
            extends AbstractConnectionProperty
    {
        public ClientTags()
        {
            super("clientTags", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class TraceToken
            extends AbstractConnectionProperty
    {
        public TraceToken()
        {
            super("traceToken", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class Ssl
            extends AbstractConnectionProperty
    {
        public Ssl()
        {
            super("SSL", NOT_REQUIRED, ALLOWED, BOOLEAN_CONVERTER);
        }
    }

    private static class SslKeyStorePath
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_SSL_ENABLED =
                checkedPredicate(properties -> SSL.getValue(properties).orElse(false));

        public SslKeyStorePath()
        {
            super("SSLKeyStorePath", NOT_REQUIRED, IF_SSL_ENABLED, STRING_CONVERTER);
        }
    }

    private static class SslKeyStorePassword
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_KEY_STORE =
                checkedPredicate(properties -> SSL_KEY_STORE_PATH.getValue(properties).isPresent());

        public SslKeyStorePassword()
        {
            super("SSLKeyStorePassword", NOT_REQUIRED, IF_KEY_STORE, STRING_CONVERTER);
        }
    }

    private static class SslKeyStoreType
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_KEY_STORE =
                checkedPredicate(properties -> SSL_KEY_STORE_PATH.getValue(properties).isPresent());

        public SslKeyStoreType()
        {
            super("SSLKeyStoreType", NOT_REQUIRED, IF_KEY_STORE, STRING_CONVERTER);
        }
    }

    private static class SslTrustStorePath
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_SSL_ENABLED =
                checkedPredicate(properties -> SSL.getValue(properties).orElse(false));

        public SslTrustStorePath()
        {
            super("SSLTrustStorePath", NOT_REQUIRED, IF_SSL_ENABLED, STRING_CONVERTER);
        }
    }

    private static class SslTrustStorePassword
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_TRUST_STORE =
                checkedPredicate(properties -> SSL_TRUST_STORE_PATH.getValue(properties).isPresent());

        public SslTrustStorePassword()
        {
            super("SSLTrustStorePassword", NOT_REQUIRED, IF_TRUST_STORE, STRING_CONVERTER);
        }
    }

    private static class SslTrustStoreType
            extends AbstractConnectionProperty
    {
        private static final Predicate IF_TRUST_STORE =
                checkedPredicate(properties -> SSL_TRUST_STORE_PATH.getValue(properties).isPresent());

        public SslTrustStoreType()
        {
            super("SSLTrustStoreType", NOT_REQUIRED, IF_TRUST_STORE, STRING_CONVERTER);
        }
    }

    private static class KerberosRemoteServiceName
            extends AbstractConnectionProperty
    {
        public KerberosRemoteServiceName()
        {
            super("KerberosRemoteServiceName", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static Predicate isKerberosEnabled()
    {
        return checkedPredicate(properties -> KERBEROS_REMOTE_SERVICE_NAME.getValue(properties).isPresent());
    }

    private static class KerberosServicePrincipalPattern
            extends AbstractConnectionProperty
    {
        public KerberosServicePrincipalPattern()
        {
            super("KerberosServicePrincipalPattern", Optional.of("${SERVICE}@${HOST}"), isKerberosEnabled(), ALLOWED, STRING_CONVERTER);
        }
    }

    private static class KerberosPrincipal
            extends AbstractConnectionProperty
    {
        public KerberosPrincipal()
        {
            super("KerberosPrincipal", NOT_REQUIRED, isKerberosEnabled(), STRING_CONVERTER);
        }
    }

    private static class KerberosUseCanonicalHostname
            extends AbstractConnectionProperty
    {
        public KerberosUseCanonicalHostname()
        {
            super("KerberosUseCanonicalHostname", Optional.of("true"), isKerberosEnabled(), ALLOWED, BOOLEAN_CONVERTER);
        }
    }

    private static class KerberosConfigPath
            extends AbstractConnectionProperty
    {
        public KerberosConfigPath()
        {
            super("KerberosConfigPath", NOT_REQUIRED, isKerberosEnabled(), FILE_CONVERTER);
        }
    }

    private static class KerberosKeytabPath
            extends AbstractConnectionProperty
    {
        public KerberosKeytabPath()
        {
            super("KerberosKeytabPath", NOT_REQUIRED, isKerberosEnabled(), FILE_CONVERTER);
        }
    }

    private static class KerberosCredentialCachePath
            extends AbstractConnectionProperty
    {
        public KerberosCredentialCachePath()
        {
            super("KerberosCredentialCachePath", NOT_REQUIRED, isKerberosEnabled(), FILE_CONVERTER);
        }
    }

    private static class AccessToken
            extends AbstractConnectionProperty
    {
        public AccessToken()
        {
            super("accessToken", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class UseSessionTimeZone
            extends AbstractConnectionProperty
    {
        public UseSessionTimeZone()
        {
            super("useSessionTimeZone", NOT_REQUIRED, ALLOWED, BOOLEAN_CONVERTER);
        }
    }

    private static class ExtraCredentials
            extends AbstractConnectionProperty>
    {
        public ExtraCredentials()
        {
            super("extraCredentials", NOT_REQUIRED, ALLOWED, ExtraCredentials::parseExtraCredentials);
        }

        // Extra credentials consists of a list of credential name value pairs.
        // E.g., `jdbc:presto://example.net:8080/?extraCredentials=abc:xyz;foo:bar` will create credentials `abc=xyz` and `foo=bar`
        public static Map parseExtraCredentials(String extraCredentialString)
        {
            return new MapPropertyParser("extraCredentials").parse(extraCredentialString);
        }
    }

    private static class SessionProperties
            extends AbstractConnectionProperty>
    {
        private static final Splitter NAME_PARTS_SPLITTER = Splitter.on('.');

        public SessionProperties()
        {
            super("sessionProperties", NOT_REQUIRED, ALLOWED, SessionProperties::parseSessionProperties);
        }

        // Session properties consists of a list of session property name value pairs.
        // E.g., `jdbc:presto://example.net:8080/?sessionProperties=abc:xyz;catalog.foo:bar` will create session properties `abc=xyz` and `catalog.foo=bar`
        public static Map parseSessionProperties(String sessionPropertiesString)
        {
            Map sessionProperties = new MapPropertyParser("sessionProperties").parse(sessionPropertiesString);
            for (String sessionPropertyName : sessionProperties.keySet()) {
                checkArgument(NAME_PARTS_SPLITTER.splitToList(sessionPropertyName).size() <= 2, "Malformed session property name: %s", sessionPropertyName);
            }
            return sessionProperties;
        }
    }

    private static class Source
            extends AbstractConnectionProperty
    {
        public Source()
        {
            super("source", NOT_REQUIRED, ALLOWED, STRING_CONVERTER);
        }
    }

    private static class MapPropertyParser
    {
        private static final CharMatcher PRINTABLE_ASCII = CharMatcher.inRange((char) 0x21, (char) 0x7E);
        private static final Splitter MAP_ENTRIES_SPLITTER = Splitter.on(';');
        private static final Splitter MAP_ENTRY_SPLITTER = Splitter.on(':');

        private final String mapName;

        private MapPropertyParser(String mapName)
        {
            this.mapName = requireNonNull(mapName, "mapName is null");
        }

        /**
         * Parses map in a form: key1:value1;key2:value2
         */
        public Map parse(String map)
        {
            return MAP_ENTRIES_SPLITTER.splitToList(map).stream()
                    .map(this::parseEntry)
                    .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
        }

        private Map.Entry parseEntry(String credential)
        {
            List keyValue = MAP_ENTRY_SPLITTER.limit(2).splitToList(credential);
            checkArgument(keyValue.size() == 2, "Malformed %s: %s", mapName, credential);
            String key = keyValue.get(0);
            String value = keyValue.get(1);
            checkArgument(!key.isEmpty(), "%s key is empty", mapName);
            checkArgument(!value.isEmpty(), "%s key is empty", mapName);

            checkArgument(PRINTABLE_ASCII.matchesAllOf(key), "%s key '%s' contains spaces or is not printable ASCII", mapName, key);
            // do not log value as it may contain sensitive information
            checkArgument(PRINTABLE_ASCII.matchesAllOf(value), "%s value for key '%s' contains spaces or is not printable ASCII", mapName, key);
            return immutableEntry(key, value);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy