| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you 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 org.apache.calcite.avatica.remote; |
| |
| import org.apache.calcite.avatica.ConnectionConfig; |
| |
| import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.File; |
| import java.lang.reflect.Constructor; |
| import java.net.URL; |
| import java.util.Objects; |
| |
| /** |
| * Default implementation of {@link AvaticaHttpClientFactory} which chooses an implementation |
| * from a property. |
| */ |
| public class AvaticaHttpClientFactoryImpl implements AvaticaHttpClientFactory { |
| private static final Logger LOG = LoggerFactory.getLogger(AvaticaHttpClientFactoryImpl.class); |
| |
| public static final String HTTP_CLIENT_IMPL_DEFAULT = |
| AvaticaCommonsHttpClientImpl.class.getName(); |
| |
| // Public for Type.PLUGIN |
| public static final AvaticaHttpClientFactoryImpl INSTANCE = new AvaticaHttpClientFactoryImpl(); |
| |
| // Public for Type.PLUGIN |
| public AvaticaHttpClientFactoryImpl() {} |
| |
| /** |
| * Returns a singleton instance of {@link AvaticaHttpClientFactoryImpl}. |
| * |
| * @return A singleton instance. |
| */ |
| public static AvaticaHttpClientFactoryImpl getInstance() { |
| return INSTANCE; |
| } |
| |
| @Override public AvaticaHttpClient getClient(URL url, ConnectionConfig config, |
| KerberosConnection kerberosUtil) { |
| String className = config.httpClientClass(); |
| if (null == className) { |
| className = HTTP_CLIENT_IMPL_DEFAULT; |
| } |
| |
| AvaticaHttpClient client = instantiateClient(className, url); |
| |
| if (client instanceof HttpClientPoolConfigurable) { |
| PoolingHttpClientConnectionManager pool = CommonsHttpClientPoolCache.getPool(config); |
| ((HttpClientPoolConfigurable) client).setHttpClientPool(pool); |
| } else { |
| // Kept for backwards compatibility, the current AvaticaCommonsHttpClientImpl |
| // does not implement these interfaces |
| if (client instanceof TrustStoreConfigurable) { |
| File truststore = config.truststore(); |
| String truststorePassword = config.truststorePassword(); |
| if (null != truststore && null != truststorePassword) { |
| ((TrustStoreConfigurable) client).setTrustStore(truststore, truststorePassword); |
| } |
| } else { |
| LOG.debug("{} is not capable of SSL/TLS communication", client.getClass().getName()); |
| } |
| |
| if (client instanceof KeyStoreConfigurable) { |
| File keystore = config.keystore(); |
| String keystorePassword = config.keystorePassword(); |
| String keyPassword = config.keyPassword(); |
| if (null != keystore && null != keystorePassword && null != keyPassword) { |
| ((KeyStoreConfigurable) client).setKeyStore(keystore, keystorePassword, keyPassword); |
| } |
| } else { |
| LOG.debug("{} is not capable of Mutual authentication", client.getClass().getName()); |
| } |
| |
| // Set the SSL hostname verification if the client supports it |
| if (client instanceof HostnameVerificationConfigurable) { |
| ((HostnameVerificationConfigurable) client) |
| .setHostnameVerification(config.hostnameVerification()); |
| } else { |
| LOG.debug("{} is not capable of configurable SSL/TLS hostname verification", |
| client.getClass().getName()); |
| } |
| } |
| |
| final String authString = config.authentication(); |
| final AuthenticationType authType = authString == null ? null |
| : AuthenticationType.valueOf(authString); |
| |
| if (client instanceof UsernamePasswordAuthenticateable) { |
| if (isUserPasswordAuth(authType)) { |
| |
| final String username = config.avaticaUser(); |
| final String password = config.avaticaPassword(); |
| |
| // Can't authenticate with NONE or w/o username and password |
| if (null != username && null != password) { |
| ((UsernamePasswordAuthenticateable) client) |
| .setUsernamePassword(authType, username, password); |
| } else { |
| LOG.debug("Username or password was null"); |
| } |
| } |
| } else { |
| LOG.debug("{} is not capable of username/password authentication.", authType); |
| } |
| |
| if (client instanceof GSSAuthenticateable) { |
| if (AuthenticationType.SPNEGO == authType) { |
| // The actual principal is set in DoAsAvaticaHttpClient below |
| ((GSSAuthenticateable) client).setGSSCredential(null); |
| } |
| } else { |
| LOG.debug("{} is not capable of kerberos authentication.", authType); |
| } |
| |
| if (null != kerberosUtil) { |
| client = new DoAsAvaticaHttpClient(client, kerberosUtil); |
| } |
| |
| return client; |
| } |
| |
| private AvaticaHttpClient instantiateClient(String className, URL url) { |
| AvaticaHttpClient client = null; |
| Exception clientCreationException = null; |
| try { |
| // Ensure that the given class is actually a subclass of AvaticaHttpClient |
| Class<? extends AvaticaHttpClient> clz = |
| Class.forName(className).asSubclass(AvaticaHttpClient.class); |
| Constructor<? extends AvaticaHttpClient> constructor = clz.getConstructor(URL.class); |
| client = constructor.newInstance(Objects.requireNonNull(url)); |
| } catch (Exception e) { |
| clientCreationException = e; |
| } |
| |
| if (client == null) { |
| throw new RuntimeException("Failed to construct AvaticaHttpClient implementation " |
| + className, clientCreationException); |
| } else { |
| return client; |
| } |
| } |
| |
| private boolean isUserPasswordAuth(AuthenticationType authType) { |
| return AuthenticationType.BASIC == authType || AuthenticationType.DIGEST == authType; |
| } |
| } |
| |
| // End AvaticaHttpClientFactoryImpl.java |