http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java deleted file mode 100644 index c37e063..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractHandler.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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.AvaticaSeverity; -import org.apache.calcite.avatica.NoSuchConnectionException; -import org.apache.calcite.avatica.remote.Service.ErrorResponse; -import org.apache.calcite.avatica.remote.Service.Request; -import org.apache.calcite.avatica.remote.Service.Response; -import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; - -import java.io.IOException; - -/** - * Abstract base class for {@link Handler}s to extend to inherit functionality common across - * serialization strategies. - * - * @param <T> The format Requests/Responses are serialized as. - */ -public abstract class AbstractHandler<T> implements Handler<T> { - private static final String NULL_EXCEPTION_MESSAGE = "(null exception message)"; - protected final Service service; - private RpcMetadataResponse metadata = null; - - public AbstractHandler(Service service) { - this.service = service; - } - - abstract Request decode(T serializedRequest) throws IOException; - - /** - * Serialize the given {@link Response} per the concrete {@link Handler} implementation. - * - * @param response The {@link Response} to serialize. - * @return A serialized representation of the {@link Response}. - * @throws IOException - */ - abstract T encode(Response response) throws IOException; - - /** - * Unwrap Avatica-specific context about a given exception. - * - * @param e A caught exception throw by Avatica implementation. - * @return An {@link ErrorResponse}. - */ - ErrorResponse unwrapException(Exception e) { - // By default, we know nothing extra. - int errorCode = ErrorResponse.UNKNOWN_ERROR_CODE; - String sqlState = ErrorResponse.UNKNOWN_SQL_STATE; - AvaticaSeverity severity = AvaticaSeverity.UNKNOWN; - String errorMsg = null; - - // Extract the contextual information if we have it. We may not. - if (e instanceof AvaticaRuntimeException) { - AvaticaRuntimeException rte = (AvaticaRuntimeException) e; - errorCode = rte.getErrorCode(); - sqlState = rte.getSqlState(); - severity = rte.getSeverity(); - errorMsg = rte.getErrorMessage(); - } else if (e instanceof NoSuchConnectionException) { - errorCode = ErrorResponse.MISSING_CONNECTION_ERROR_CODE; - severity = AvaticaSeverity.ERROR; - errorMsg = e.getMessage(); - } else { - // Try to construct a meaningful error message when the server impl doesn't provide one. - errorMsg = getCausalChain(e); - } - - return new ErrorResponse(e, errorMsg, errorCode, sqlState, severity, metadata); - } - - /** - * Compute a response for the given request, handling errors generated by that computation. - * - * @param serializedRequest The caller's request. - * @return A {@link Response} with additional context about that response. - */ - public HandlerResponse<T> apply(T serializedRequest) { - try { - final Service.Request request = decode(serializedRequest); - final Service.Response response = request.accept(service); - return new HandlerResponse<>(encode(response), HTTP_OK); - } catch (Exception e) { - return convertToErrorResponse(e); - } - } - - /** - * Attempts to convert an Exception to an ErrorResponse. If there is an issue in serialization, - * a RuntimeException is thrown instead (wrapping the original exception if necessary). - * - * @param e The exception to convert. - * @return A HandlerResponse instance. - */ - public HandlerResponse<T> convertToErrorResponse(Exception e) { - ErrorResponse errorResp = unwrapException(e); - - try { - return new HandlerResponse<>(encode(errorResp), HTTP_INTERNAL_SERVER_ERROR); - } catch (IOException e1) { - // TODO provide a canned ErrorResponse - - // If we can't serialize the error message, we can't give a meaningful error to caller. - // Just try to not unnecessarily create more exceptions. - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - - throw new RuntimeException(e); - } - } - - /** - * Constructs a message for the summary of an Exception. - * - * @param e The Exception to summarize. - * @return A summary message for the Exception. - */ - private String getCausalChain(Exception e) { - StringBuilder sb = new StringBuilder(16); - Throwable curr = e; - // Could use Guava, but that would increase dependency set unnecessarily. - while (null != curr) { - if (sb.length() > 0) { - sb.append(" -> "); - } - String message = curr.getMessage(); - sb.append(curr.getClass().getSimpleName()).append(": "); - sb.append(null == message ? NULL_EXCEPTION_MESSAGE : message); - curr = curr.getCause(); - } - if (sb.length() == 0) { - // Catch the case where we have no error message. - return "Unknown error message"; - } - return sb.toString(); - } - - @Override public void setRpcMetadata(RpcMetadataResponse metadata) { - this.metadata = metadata; - } -} - -// End AbstractHandler.java
http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java deleted file mode 100644 index ffaa360..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.ColumnMetaData; -import org.apache.calcite.avatica.Meta; - -import java.sql.Types; -import java.util.ArrayList; -import java.util.List; - -/** - * A common base class for {@link Service} implementations that implement - * modifications made to response objects. - */ -public abstract class AbstractService implements Service { - - private RpcMetadataResponse rpcMetadata = null; - - /** - * Represents the serialization of the data over a transport. - */ - enum SerializationType { - JSON, - PROTOBUF - } - - /** - * @return The manner in which the data is serialized. - */ - abstract SerializationType getSerializationType(); - - /** Modifies a signature, changing the representation of numeric columns - * within it. This deals with the fact that JSON transmits a small long value, - * or a float which is a whole number, as an integer. Thus the accessors need - * be prepared to accept any numeric type. */ - Meta.Signature finagle(Meta.Signature signature) { - final List<ColumnMetaData> columns = new ArrayList<>(); - for (ColumnMetaData column : signature.columns) { - columns.add(finagle(column)); - } - if (columns.equals(signature.columns)) { - return signature; - } - return new Meta.Signature(columns, signature.sql, - signature.parameters, signature.internalParameters, - signature.cursorFactory, signature.statementType); - } - - ColumnMetaData finagle(ColumnMetaData column) { - switch (column.type.rep) { - case BYTE: - case PRIMITIVE_BYTE: - case DOUBLE: - case PRIMITIVE_DOUBLE: - case FLOAT: - case PRIMITIVE_FLOAT: - case INTEGER: - case PRIMITIVE_INT: - case SHORT: - case PRIMITIVE_SHORT: - case LONG: - case PRIMITIVE_LONG: - return column.setRep(ColumnMetaData.Rep.NUMBER); - default: - // continue - break; - } - switch (column.type.id) { - case Types.VARBINARY: - case Types.BINARY: - switch (getSerializationType()) { - case JSON: - return column.setRep(ColumnMetaData.Rep.STRING); - case PROTOBUF: - return column; - default: - throw new IllegalStateException("Unhadled case statement"); - } - case Types.DECIMAL: - case Types.NUMERIC: - return column.setRep(ColumnMetaData.Rep.NUMBER); - default: - return column; - } - } - - PrepareResponse finagle(PrepareResponse response) { - final Meta.StatementHandle statement = finagle(response.statement); - if (statement == response.statement) { - return response; - } - return new PrepareResponse(statement, rpcMetadata); - } - - Meta.StatementHandle finagle(Meta.StatementHandle h) { - final Meta.Signature signature = finagle(h.signature); - if (signature == h.signature) { - return h; - } - return new Meta.StatementHandle(h.connectionId, h.id, signature); - } - - ResultSetResponse finagle(ResultSetResponse r) { - if (r.updateCount != -1) { - assert r.signature == null; - return r; - } - if (r.signature == null) { - return r; - } - final Meta.Signature signature = finagle(r.signature); - if (signature == r.signature) { - return r; - } - return new ResultSetResponse(r.connectionId, r.statementId, r.ownStatement, - signature, r.firstFrame, r.updateCount, rpcMetadata); - } - - ExecuteResponse finagle(ExecuteResponse r) { - if (r.missingStatement) { - return r; - } - final List<ResultSetResponse> results = new ArrayList<>(); - int changeCount = 0; - for (ResultSetResponse result : r.results) { - ResultSetResponse result2 = finagle(result); - if (result2 != result) { - ++changeCount; - } - results.add(result2); - } - if (changeCount == 0) { - return r; - } - return new ExecuteResponse(results, r.missingStatement, rpcMetadata); - } - - @Override public void setRpcMetadata(RpcMetadataResponse metadata) { - // OK if this is null - this.rpcMetadata = metadata; - } -} - -// End AbstractService.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AuthenticationType.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AuthenticationType.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AuthenticationType.java deleted file mode 100644 index 2662e14..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AuthenticationType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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; - -/** - * An enumeration for support types of authentication for the HttpServer. - */ -public enum AuthenticationType { - NONE, - BASIC, - DIGEST, - SPNEGO; -} - -// End AuthenticationType.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java deleted file mode 100644 index 33872d0..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientImpl.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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.http.HttpHost; -import org.apache.http.NoHttpResponseException; -import org.apache.http.auth.AuthSchemeProvider; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.AuthSchemes; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.Lookup; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.socket.PlainConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.auth.BasicSchemeFactory; -import org.apache.http.impl.auth.DigestSchemeFactory; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.ssl.SSLContexts; -import org.apache.http.util.EntityUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Objects; - -import javax.net.ssl.SSLContext; - -/** - * A common class to invoke HTTP requests against the Avatica server agnostic of the data being - * sent and received across the wire. - */ -public class AvaticaCommonsHttpClientImpl implements AvaticaHttpClient, - UsernamePasswordAuthenticateable, TrustStoreConfigurable { - private static final Logger LOG = LoggerFactory.getLogger(AvaticaCommonsHttpClientImpl.class); - - // Some basic exposed configurations - private static final String MAX_POOLED_CONNECTION_PER_ROUTE_KEY = - "avatica.pooled.connections.per.route"; - private static final String MAX_POOLED_CONNECTION_PER_ROUTE_DEFAULT = "25"; - private static final String MAX_POOLED_CONNECTIONS_KEY = "avatica.pooled.connections.max"; - private static final String MAX_POOLED_CONNECTIONS_DEFAULT = "100"; - - protected final HttpHost host; - protected final URI uri; - protected BasicAuthCache authCache; - protected CloseableHttpClient client; - PoolingHttpClientConnectionManager pool; - - protected UsernamePasswordCredentials credentials = null; - protected CredentialsProvider credentialsProvider = null; - protected Lookup<AuthSchemeProvider> authRegistry = null; - - protected File truststore = null; - protected String truststorePassword = null; - - public AvaticaCommonsHttpClientImpl(URL url) { - this.host = new HttpHost(url.getHost(), url.getPort(), url.getProtocol()); - this.uri = toURI(Objects.requireNonNull(url)); - initializeClient(); - } - - private void initializeClient() { - SSLConnectionSocketFactory sslFactory = null; - if (null != truststore && null != truststorePassword) { - try { - SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial( - truststore, truststorePassword.toCharArray()).build(); - sslFactory = new SSLConnectionSocketFactory(sslcontext); - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - LOG.debug("Not configuring HTTPS because of missing truststore/password"); - } - - RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create(); - registryBuilder.register("http", PlainConnectionSocketFactory.getSocketFactory()); - // Only register the SSL factory when provided - if (null != sslFactory) { - registryBuilder.register("https", sslFactory); - } - pool = new PoolingHttpClientConnectionManager(registryBuilder.build()); - // Increase max total connection to 100 - final String maxCnxns = - System.getProperty(MAX_POOLED_CONNECTIONS_KEY, - MAX_POOLED_CONNECTIONS_DEFAULT); - pool.setMaxTotal(Integer.parseInt(maxCnxns)); - // Increase default max connection per route to 25 - final String maxCnxnsPerRoute = System.getProperty(MAX_POOLED_CONNECTION_PER_ROUTE_KEY, - MAX_POOLED_CONNECTION_PER_ROUTE_DEFAULT); - pool.setDefaultMaxPerRoute(Integer.parseInt(maxCnxnsPerRoute)); - - this.authCache = new BasicAuthCache(); - - // A single thread-safe HttpClient, pooling connections via the ConnectionManager - this.client = HttpClients.custom().setConnectionManager(pool).build(); - } - - public byte[] send(byte[] request) { - while (true) { - HttpClientContext context = HttpClientContext.create(); - - context.setTargetHost(host); - - // Set the credentials if they were provided. - if (null != this.credentials) { - context.setCredentialsProvider(credentialsProvider); - context.setAuthSchemeRegistry(authRegistry); - context.setAuthCache(authCache); - } - - ByteArrayEntity entity = new ByteArrayEntity(request, ContentType.APPLICATION_OCTET_STREAM); - - // Create the client with the AuthSchemeRegistry and manager - HttpPost post = new HttpPost(uri); - post.setEntity(entity); - - try (CloseableHttpResponse response = execute(post, context)) { - final int statusCode = response.getStatusLine().getStatusCode(); - if (HttpURLConnection.HTTP_OK == statusCode - || HttpURLConnection.HTTP_INTERNAL_ERROR == statusCode) { - return EntityUtils.toByteArray(response.getEntity()); - } else if (HttpURLConnection.HTTP_UNAVAILABLE == statusCode) { - LOG.debug("Failed to connect to server (HTTP/503), retrying"); - continue; - } - - throw new RuntimeException("Failed to execute HTTP Request, got HTTP/" + statusCode); - } catch (NoHttpResponseException e) { - // This can happen when sitting behind a load balancer and a backend server dies - LOG.debug("The server failed to issue an HTTP response, retrying"); - continue; - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - LOG.debug("Failed to execute HTTP request", e); - throw new RuntimeException(e); - } - } - } - - // Visible for testing - CloseableHttpResponse execute(HttpPost post, HttpClientContext context) - throws IOException, ClientProtocolException { - return client.execute(post, context); - } - - @Override public void setUsernamePassword(AuthenticationType authType, String username, - String password) { - this.credentials = new UsernamePasswordCredentials( - Objects.requireNonNull(username), Objects.requireNonNull(password)); - - this.credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, credentials); - - RegistryBuilder<AuthSchemeProvider> authRegistryBuilder = RegistryBuilder.create(); - switch (authType) { - case BASIC: - authRegistryBuilder.register(AuthSchemes.BASIC, new BasicSchemeFactory()); - break; - case DIGEST: - authRegistryBuilder.register(AuthSchemes.DIGEST, new DigestSchemeFactory()); - break; - default: - throw new IllegalArgumentException("Unsupported authentiation type: " + authType); - } - this.authRegistry = authRegistryBuilder.build(); - } - - private static URI toURI(URL url) throws RuntimeException { - try { - return url.toURI(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - @Override public void setTrustStore(File truststore, String password) { - this.truststore = Objects.requireNonNull(truststore); - if (!truststore.exists() || !truststore.isFile()) { - throw new IllegalArgumentException( - "Truststore is must be an existing, regular file: " + truststore); - } - this.truststorePassword = Objects.requireNonNull(password); - initializeClient(); - } -} - -// End AvaticaCommonsHttpClientImpl.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientSpnegoImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientSpnegoImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientSpnegoImpl.java deleted file mode 100644 index c1ca658..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaCommonsHttpClientSpnegoImpl.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * 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.http.HttpHost; -import org.apache.http.auth.AuthSchemeProvider; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.KerberosCredentials; -import org.apache.http.client.config.AuthSchemes; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.Lookup; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.entity.ByteArrayEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.auth.SPNegoSchemeFactory; -import org.apache.http.impl.client.BasicAuthCache; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.util.EntityUtils; - -import org.ietf.jgss.GSSCredential; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.Principal; -import java.util.Objects; - -/** - * Implementation of an AvaticaHttpClient which uses SPNEGO. - */ -public class AvaticaCommonsHttpClientSpnegoImpl implements AvaticaHttpClient { - private static final Logger LOG = LoggerFactory - .getLogger(AvaticaCommonsHttpClientSpnegoImpl.class); - - public static final String CACHED_CONNECTIONS_MAX_KEY = "avatica.http.spnego.max_cached"; - public static final String CACHED_CONNECTIONS_MAX_DEFAULT = "100"; - public static final String CACHED_CONNECTIONS_MAX_PER_ROUTE_KEY = - "avatica.http.spnego.max_per_route"; - public static final String CACHED_CONNECTIONS_MAX_PER_ROUTE_DEFAULT = "25"; - - private static final boolean USE_CANONICAL_HOSTNAME = true; - private static final boolean STRIP_PORT_ON_SERVER_LOOKUP = true; - - final URL url; - final HttpHost host; - final PoolingHttpClientConnectionManager pool; - final Lookup<AuthSchemeProvider> authRegistry; - final BasicCredentialsProvider credentialsProvider; - final BasicAuthCache authCache; - final CloseableHttpClient client; - - /** - * Constructs an http client with the expectation that the user is already logged in with their - * Kerberos identity via JAAS. - * - * @param url The URL for the Avatica server - */ - public AvaticaCommonsHttpClientSpnegoImpl(URL url) { - this(url, null); - } - - /** - * Constructs an HTTP client with user specified by the given credentials. - * - * @param url The URL for the Avatica server - * @param credential The GSS credentials - */ - public AvaticaCommonsHttpClientSpnegoImpl(URL url, GSSCredential credential) { - this.url = Objects.requireNonNull(url); - - pool = new PoolingHttpClientConnectionManager(); - // Increase max total connection to 100 - final String maxCnxns = - System.getProperty(CACHED_CONNECTIONS_MAX_KEY, CACHED_CONNECTIONS_MAX_DEFAULT); - pool.setMaxTotal(Integer.parseInt(maxCnxns)); - // Increase default max connection per route to 25 - final String maxCnxnsPerRoute = System.getProperty(CACHED_CONNECTIONS_MAX_PER_ROUTE_KEY, - CACHED_CONNECTIONS_MAX_PER_ROUTE_DEFAULT); - pool.setDefaultMaxPerRoute(Integer.parseInt(maxCnxnsPerRoute)); - - this.host = new HttpHost(url.getHost(), url.getPort()); - - this.authRegistry = RegistryBuilder.<AuthSchemeProvider>create().register(AuthSchemes.SPNEGO, - new SPNegoSchemeFactory(STRIP_PORT_ON_SERVER_LOOKUP, USE_CANONICAL_HOSTNAME)).build(); - - this.credentialsProvider = new BasicCredentialsProvider(); - if (null != credential) { - // Non-null credential should be used directly with KerberosCredentials. - this.credentialsProvider.setCredentials(AuthScope.ANY, new KerberosCredentials(credential)); - } else { - // A null credential implies that the user is logged in via JAAS using the - // java.security.auth.login.config system property - this.credentialsProvider.setCredentials(AuthScope.ANY, EmptyCredentials.INSTANCE); - } - - this.authCache = new BasicAuthCache(); - - // A single thread-safe HttpClient, pooling connections via the ConnectionManager - this.client = HttpClients.custom() - .setDefaultAuthSchemeRegistry(authRegistry) - .setConnectionManager(pool).build(); - } - - @Override public byte[] send(byte[] request) { - HttpClientContext context = HttpClientContext.create(); - - context.setTargetHost(host); - context.setCredentialsProvider(credentialsProvider); - context.setAuthSchemeRegistry(authRegistry); - context.setAuthCache(authCache); - - ByteArrayEntity entity = new ByteArrayEntity(request, ContentType.APPLICATION_OCTET_STREAM); - - // Create the client with the AuthSchemeRegistry and manager - HttpPost post = new HttpPost(toURI(url)); - post.setEntity(entity); - - try (CloseableHttpResponse response = client.execute(post, context)) { - final int statusCode = response.getStatusLine().getStatusCode(); - if (HttpURLConnection.HTTP_OK == statusCode - || HttpURLConnection.HTTP_INTERNAL_ERROR == statusCode) { - return EntityUtils.toByteArray(response.getEntity()); - } - - throw new RuntimeException("Failed to execute HTTP Request, got HTTP/" + statusCode); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - LOG.debug("Failed to execute HTTP request", e); - throw new RuntimeException(e); - } - } - - private static URI toURI(URL url) throws RuntimeException { - try { - return url.toURI(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - /** - * A credentials implementation which returns null. - */ - private static class EmptyCredentials implements Credentials { - public static final EmptyCredentials INSTANCE = new EmptyCredentials(); - - @Override public String getPassword() { - return null; - } - @Override public Principal getUserPrincipal() { - return null; - } - } -} - -// End AvaticaCommonsHttpClientSpnegoImpl.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClient.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClient.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClient.java deleted file mode 100644 index eac1b74..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClient.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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; - -/** - * An interface which defines how requests are sent to the Avatica server. - */ -public interface AvaticaHttpClient { - - /** - * Sends a serialized request to the Avatica server. - * - * @param request The serialized request. - * @return The serialized response. - */ - byte[] send(byte[] request); - -} - -// End AvaticaHttpClient.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactory.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactory.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactory.java deleted file mode 100644 index efb3c49..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 java.net.URL; - -/** - * A factory for constructing {@link AvaticaHttpClient}'s. - */ -public interface AvaticaHttpClientFactory { - - /** - * Construct the appropriate implementation of {@link AvaticaHttpClient}. - * - * @param url URL that the client is for. - * @param config Configuration to use when constructing the implementation. - * @return An instance of {@link AvaticaHttpClient}. - */ - AvaticaHttpClient getClient(URL url, ConnectionConfig config, KerberosConnection kerberosUtil); - -} - -// End AvaticaHttpClientFactory.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java deleted file mode 100644 index 8778c3d..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientFactoryImpl.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.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 static final String SPNEGO_HTTP_CLIENT_IMPL_DEFAULT = - AvaticaCommonsHttpClientSpnegoImpl.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) { - // Provide an implementation that works with SPNEGO if that's the authentication is use. - if ("SPNEGO".equalsIgnoreCase(config.authentication())) { - className = SPNEGO_HTTP_CLIENT_IMPL_DEFAULT; - } else { - className = HTTP_CLIENT_IMPL_DEFAULT; - } - } - - AvaticaHttpClient client = instantiateClient(className, url); - if (null != kerberosUtil) { - client = new DoAsAvaticaHttpClient(client, kerberosUtil); - } - - 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 UsernamePasswordAuthenticateable) { - // Shortcircuit quickly if authentication wasn't provided (implies NONE) - final String authString = config.authentication(); - if (null == authString) { - return client; - } - - final AuthenticationType authType = AuthenticationType.valueOf(authString); - final String username = config.avaticaUser(); - final String password = config.avaticaPassword(); - - // Can't authenticate with NONE or w/o username and password - if (isUserPasswordAuth(authType)) { - 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); - } - } - - return client; - } - - private AvaticaHttpClient instantiateClient(String className, URL url) { - try { - Class<?> clz = Class.forName(className); - Constructor<?> constructor = clz.getConstructor(URL.class); - Object instance = constructor.newInstance(Objects.requireNonNull(url)); - return AvaticaHttpClient.class.cast(instance); - } catch (Exception e) { - throw new RuntimeException("Failed to construct AvaticaHttpClient implementation " - + className, e); - } - } - - private boolean isUserPasswordAuth(AuthenticationType authType) { - return AuthenticationType.BASIC == authType || AuthenticationType.DIGEST == authType; - } -} - -// End AvaticaHttpClientFactoryImpl.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientImpl.java deleted file mode 100644 index c100eec..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaHttpClientImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.AvaticaUtils; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -/** - * A common class to invoke HTTP requests against the Avatica server agnostic of the data being - * sent and received across the wire. - */ -public class AvaticaHttpClientImpl implements AvaticaHttpClient { - protected final URL url; - - public AvaticaHttpClientImpl(URL url) { - this.url = url; - } - - public byte[] send(byte[] request) { - // TODO back-off policy? - while (true) { - try { - final HttpURLConnection connection = openConnection(); - connection.setRequestMethod("POST"); - connection.setDoInput(true); - connection.setDoOutput(true); - try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { - wr.write(request); - wr.flush(); - wr.close(); - } - final int responseCode = connection.getResponseCode(); - final InputStream inputStream; - if (responseCode == HttpURLConnection.HTTP_UNAVAILABLE) { - // Could be sitting behind a load-balancer, try again. - continue; - } else if (responseCode != HttpURLConnection.HTTP_OK) { - inputStream = connection.getErrorStream(); - } else { - inputStream = connection.getInputStream(); - } - return AvaticaUtils.readFullyToBytes(inputStream); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - HttpURLConnection openConnection() throws IOException { - return (HttpURLConnection) url.openConnection(); - } -} - -// End AvaticaHttpClientImpl.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionConfigImpl.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionConfigImpl.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionConfigImpl.java deleted file mode 100644 index d5ae9b1..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionConfigImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.ConnectionConfigImpl; - -import java.util.Properties; - -/** Implementation of {@link org.apache.calcite.avatica.ConnectionConfig} - * with extra properties specific to Remote Driver. */ -public class AvaticaRemoteConnectionConfigImpl extends ConnectionConfigImpl { - public AvaticaRemoteConnectionConfigImpl(Properties properties) { - super(properties); - } - - public Service.Factory factory() { - return AvaticaRemoteConnectionProperty.FACTORY.wrap(properties) - .getPlugin(Service.Factory.class, null); - } -} - -// End AvaticaRemoteConnectionConfigImpl.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java deleted file mode 100644 index e965989..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRemoteConnectionProperty.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.ConnectionProperty; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; - -import static org.apache.calcite.avatica.ConnectionConfigImpl.PropEnv; -import static org.apache.calcite.avatica.ConnectionConfigImpl.parse; - -/** - * Enumeration of Avatica remote driver's built-in connection properties. - */ -public enum AvaticaRemoteConnectionProperty implements ConnectionProperty { - /** Factory. */ - FACTORY("factory", Type.STRING, null); - - private final String camelName; - private final Type type; - private final Object defaultValue; - - private static final Map<String, AvaticaRemoteConnectionProperty> NAME_TO_PROPS; - - static { - NAME_TO_PROPS = new HashMap<>(); - for (AvaticaRemoteConnectionProperty p - : AvaticaRemoteConnectionProperty.values()) { - NAME_TO_PROPS.put(p.camelName.toUpperCase(Locale.ROOT), p); - NAME_TO_PROPS.put(p.name(), p); - } - } - - AvaticaRemoteConnectionProperty(String camelName, - Type type, - Object defaultValue) { - this.camelName = camelName; - this.type = type; - this.defaultValue = defaultValue; - assert type.valid(defaultValue, type.defaultValueClass()); - } - - public String camelName() { - return camelName; - } - - public Object defaultValue() { - return defaultValue; - } - - public Type type() { - return type; - } - - public Class valueClass() { - return type.defaultValueClass(); - } - - public PropEnv wrap(Properties properties) { - return new PropEnv(parse(properties, NAME_TO_PROPS), this); - } - - public boolean required() { - return false; - } -} - -// End AvaticaRemoteConnectionProperty.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRuntimeException.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRuntimeException.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRuntimeException.java deleted file mode 100644 index 2f9a1cd..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/AvaticaRuntimeException.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.AvaticaSeverity; -import org.apache.calcite.avatica.remote.Service.ErrorResponse; - -import java.util.Objects; - -/** - * A {@link RuntimeException} thrown by Avatica with additional contextual information about - * what happened to cause the Exception. - */ -public class AvaticaRuntimeException extends RuntimeException { - private static final long serialVersionUID = 1L; - private final String errorMessage; - private final int errorCode; - private final String sqlState; - private final AvaticaSeverity severity; - - /** - * Constructs an {@code AvaticaRuntimeException} with no additional information. - * - * <p>It is strongly preferred that the caller invoke - * {@link #AvaticaRuntimeException(String, int, String, AvaticaSeverity)} - * with proper contextual information. - */ - public AvaticaRuntimeException() { - this("No additional context on exception", ErrorResponse.UNKNOWN_ERROR_CODE, - ErrorResponse.UNKNOWN_SQL_STATE, AvaticaSeverity.UNKNOWN); - } - - /** - * Constructs an {@code AvaticaRuntimeException} with the given - * contextual information surrounding the error. - * - * @param errorMessage A human-readable explanation about what happened - * @param errorCode Numeric identifier for error - * @param sqlState 5-character identifier for error - * @param severity Severity - */ - public AvaticaRuntimeException(String errorMessage, int errorCode, String sqlState, - AvaticaSeverity severity) { - this.errorMessage = Objects.requireNonNull(errorMessage); - this.errorCode = errorCode; - this.sqlState = Objects.requireNonNull(sqlState); - this.severity = Objects.requireNonNull(severity); - } - - /** - * Returns a human-readable error message. - */ - public String getErrorMessage() { - return errorMessage; - } - - /** - * Returns a numeric code for this error. - */ - public int getErrorCode() { - return errorCode; - } - - /** - * Returns the five-character identifier for this error. - */ - public String getSqlState() { - return sqlState; - } - - /** - * Returns the severity at which this exception is thrown. - */ - public AvaticaSeverity getSeverity() { - return severity; - } - - @Override public String toString() { - StringBuilder sb = new StringBuilder(64); - return sb.append("AvaticaRuntimeException: [") - .append("Messsage: '").append(errorMessage).append("', ") - .append("Error code: '").append(errorCode).append("', ") - .append("SQL State: '").append(sqlState).append("', ") - .append("Severity: '").append(severity).append("']").toString(); - } -} - -// End AvaticaRuntimeException.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java deleted file mode 100644 index e06760d..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 java.security.PrivilegedAction; -import java.util.Objects; - -import javax.security.auth.Subject; - -/** - * HTTP client implementation which invokes the wrapped HTTP client in a doAs with the provided - * Subject. - */ -public class DoAsAvaticaHttpClient implements AvaticaHttpClient { - private final AvaticaHttpClient wrapped; - private final KerberosConnection kerberosUtil; - - public DoAsAvaticaHttpClient(AvaticaHttpClient wrapped, KerberosConnection kerberosUtil) { - this.wrapped = Objects.requireNonNull(wrapped); - this.kerberosUtil = Objects.requireNonNull(kerberosUtil); - } - - @Override public byte[] send(final byte[] request) { - return Subject.doAs(kerberosUtil.getSubject(), new PrivilegedAction<byte[]>() { - @Override public byte[] run() { - return wrapped.send(request); - } - }); - } -} - -// End DoAsAvaticaHttpClient.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java deleted file mode 100644 index 3f6d4df..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Driver.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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.AvaticaConnection; -import org.apache.calcite.avatica.BuiltInConnectionProperty; -import org.apache.calcite.avatica.ConnectionConfig; -import org.apache.calcite.avatica.ConnectionProperty; -import org.apache.calcite.avatica.DriverVersion; -import org.apache.calcite.avatica.Meta; -import org.apache.calcite.avatica.UnregisteredDriver; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.MalformedURLException; -import java.net.URL; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Properties; - -/** - * Avatica Remote JDBC driver. - */ -public class Driver extends UnregisteredDriver { - private static final Logger LOG = LoggerFactory.getLogger(Driver.class); - - public static final String CONNECT_STRING_PREFIX = "jdbc:avatica:remote:"; - - static { - new Driver().register(); - } - - public Driver() { - super(); - } - - /** - * Defines the method of message serialization used by the Driver - */ - public static enum Serialization { - JSON, - PROTOBUF; - } - - @Override protected String getConnectStringPrefix() { - return CONNECT_STRING_PREFIX; - } - - protected DriverVersion createDriverVersion() { - return DriverVersion.load( - Driver.class, - "org-apache-calcite-jdbc.properties", - "Avatica Remote JDBC Driver", - "unknown version", - "Avatica", - "unknown version"); - } - - @Override protected Collection<ConnectionProperty> getConnectionProperties() { - final List<ConnectionProperty> list = new ArrayList<ConnectionProperty>(); - Collections.addAll(list, BuiltInConnectionProperty.values()); - Collections.addAll(list, AvaticaRemoteConnectionProperty.values()); - return list; - } - - @Override public Meta createMeta(AvaticaConnection connection) { - final ConnectionConfig config = connection.config(); - - // Perform the login and launch the renewal thread if necessary - final KerberosConnection kerberosUtil = createKerberosUtility(config); - if (null != kerberosUtil) { - kerberosUtil.login(); - connection.setKerberosConnection(kerberosUtil); - } - - // Create a single Service and set it on the Connection instance - final Service service = createService(connection, config); - connection.setService(service); - return new RemoteMeta(connection, service); - } - - KerberosConnection createKerberosUtility(ConnectionConfig config) { - final String principal = config.kerberosPrincipal(); - if (null != principal) { - return new KerberosConnection(principal, config.kerberosKeytab()); - } - return null; - } - - /** - * Creates a {@link Service} with the given {@link AvaticaConnection} and configuration. - * - * @param connection The {@link AvaticaConnection} to use. - * @param config Configuration properties - * @return A Service implementation. - */ - Service createService(AvaticaConnection connection, ConnectionConfig config) { - final Service.Factory metaFactory = config.factory(); - final Service service; - if (metaFactory != null) { - service = metaFactory.create(connection); - } else if (config.url() != null) { - final AvaticaHttpClient httpClient = getHttpClient(connection, config); - final Serialization serializationType = getSerialization(config); - - LOG.debug("Instantiating {} service", serializationType); - switch (serializationType) { - case JSON: - service = new RemoteService(httpClient); - break; - case PROTOBUF: - service = new RemoteProtobufService(httpClient, new ProtobufTranslationImpl()); - break; - default: - throw new IllegalArgumentException("Unhandled serialization type: " + serializationType); - } - } else { - service = new MockJsonService(Collections.<String, String>emptyMap()); - } - return service; - } - - /** - * Creates the HTTP client that communicates with the Avatica server. - * - * @param connection The {@link AvaticaConnection}. - * @param config The configuration. - * @return An {@link AvaticaHttpClient} implementation. - */ - AvaticaHttpClient getHttpClient(AvaticaConnection connection, ConnectionConfig config) { - URL url; - try { - url = new URL(config.url()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - - AvaticaHttpClientFactory httpClientFactory = config.httpClientFactory(); - - return httpClientFactory.getClient(url, config, connection.getKerberosConnection()); - } - - @Override public Connection connect(String url, Properties info) - throws SQLException { - AvaticaConnection conn = (AvaticaConnection) super.connect(url, info); - if (conn == null) { - // It's not an url for our driver - return null; - } - - Service service = conn.getService(); - - // super.connect(...) should be creating a service and setting it in the AvaticaConnection - assert null != service; - - service.apply( - new Service.OpenConnectionRequest(conn.id, - Service.OpenConnectionRequest.serializeProperties(info))); - - return conn; - } - - Serialization getSerialization(ConnectionConfig config) { - final String serializationStr = config.serialization(); - Serialization serializationType = Serialization.JSON; - if (null != serializationStr) { - try { - serializationType = - Serialization.valueOf(serializationStr.toUpperCase(Locale.ROOT)); - } catch (Exception e) { - // Log a warning instead of failing harshly? Intentionally no loggers available? - throw new RuntimeException(e); - } - } - - return serializationType; - } -} - -// End Driver.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Handler.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Handler.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Handler.java deleted file mode 100644 index 30d026c..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/Handler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.remote.Service.RpcMetadataResponse; - -import java.util.Objects; - -/** - * API for text request-response calls to an Avatica server. - * - * @param <T> The type this handler accepts and returns - */ -public interface Handler<T> { - int HTTP_OK = 200; - int HTTP_INTERNAL_SERVER_ERROR = 500; - String HANDLER_SERIALIZATION_METRICS_NAME = "Handler.Serialization"; - - /** - * Struct that encapsulates the context of the result of a request to Avatica. - */ - public class HandlerResponse<T> { - private final T response; - private final int statusCode; - - public HandlerResponse(T response, int statusCode) { - this.response = Objects.requireNonNull(response); - this.statusCode = statusCode; - } - - public T getResponse() { - return response; - } - - public int getStatusCode() { - return statusCode; - } - - @Override public String toString() { - return "Response: " + response + ", Status:" + statusCode; - } - } - - HandlerResponse<T> apply(T request); - - /** - * Sets some general server information to return to the client in all responses. - * - * @param metadata Server-wide information - */ - void setRpcMetadata(RpcMetadataResponse metadata); -} - -// End Handler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java deleted file mode 100644 index fd57078..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.metrics.MetricsSystem; -import org.apache.calcite.avatica.metrics.Timer; -import org.apache.calcite.avatica.metrics.Timer.Context; -import org.apache.calcite.avatica.remote.Service.Request; -import org.apache.calcite.avatica.remote.Service.Response; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; -import java.io.StringWriter; - -/** - * Implementation of {@link org.apache.calcite.avatica.remote.Handler} - * that decodes JSON requests, sends them to a {@link Service}, - * and encodes the responses into JSON. - * - * @see org.apache.calcite.avatica.remote.JsonService - */ -public class JsonHandler extends AbstractHandler<String> { - - protected static final ObjectMapper MAPPER = JsonService.MAPPER; - - final MetricsSystem metrics; - final Timer serializationTimer; - - public JsonHandler(Service service, MetricsSystem metrics) { - super(service); - this.metrics = metrics; - this.serializationTimer = this.metrics.getTimer( - MetricsHelper.concat(JsonHandler.class, HANDLER_SERIALIZATION_METRICS_NAME)); - } - - public HandlerResponse<String> apply(String jsonRequest) { - return super.apply(jsonRequest); - } - - @Override Request decode(String request) throws IOException { - try (final Context ctx = serializationTimer.start()) { - return MAPPER.readValue(request, Service.Request.class); - } - } - - /** - * Serializes the provided object as JSON. - * - * @param response The object to serialize. - * @return A JSON string. - */ - @Override String encode(Response response) throws IOException { - try (final Context ctx = serializationTimer.start()) { - final StringWriter w = new StringWriter(); - MAPPER.writeValue(w, response); - return w.toString(); - } - } -} - -// End JsonHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonService.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonService.java b/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonService.java deleted file mode 100644 index 19c95e7..0000000 --- a/avatica/core/src/main/java/org/apache/calcite/avatica/remote/JsonService.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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 com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; -import java.io.StringWriter; - -/** - * Implementation of {@link org.apache.calcite.avatica.remote.Service} - * that encodes requests and responses as JSON. - */ -public abstract class JsonService extends AbstractService { - public static final ObjectMapper MAPPER; - static { - MAPPER = new ObjectMapper(); - MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); - MAPPER.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true); - } - - public JsonService() { - } - - /** Derived class should implement this method to transport requests and - * responses to and from the peer service. */ - public abstract String apply(String request); - - @Override SerializationType getSerializationType() { - return SerializationType.JSON; - } - - //@VisibleForTesting - protected static <T> T decode(String response, Class<T> expectedType) - throws IOException { - Response resp = MAPPER.readValue(response, Response.class); - if (resp instanceof ErrorResponse) { - throw ((ErrorResponse) resp).toException(); - } else if (!expectedType.isAssignableFrom(resp.getClass())) { - throw new ClassCastException("Cannot cast " + resp.getClass() + " into " + expectedType); - } - - return expectedType.cast(resp); - } - - //@VisibleForTesting - protected static <T> String encode(T request) throws IOException { - final StringWriter w = new StringWriter(); - MAPPER.writeValue(w, request); - return w.toString(); - } - - protected RuntimeException handle(IOException e) { - return new RuntimeException(e); - } - - public ResultSetResponse apply(CatalogsRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ResultSetResponse apply(SchemasRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ResultSetResponse apply(TablesRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ResultSetResponse apply(TableTypesRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ResultSetResponse apply(TypeInfoRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ResultSetResponse apply(ColumnsRequest request) { - try { - return finagle(decode(apply(encode(request)), ResultSetResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public PrepareResponse apply(PrepareRequest request) { - try { - return finagle(decode(apply(encode(request)), PrepareResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public ExecuteResponse apply(PrepareAndExecuteRequest request) { - try { - return finagle(decode(apply(encode(request)), ExecuteResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public FetchResponse apply(FetchRequest request) { - try { - return decode(apply(encode(request)), FetchResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public ExecuteResponse apply(ExecuteRequest request) { - try { - return finagle(decode(apply(encode(request)), ExecuteResponse.class)); - } catch (IOException e) { - throw handle(e); - } - } - - public CreateStatementResponse apply(CreateStatementRequest request) { - try { - return decode(apply(encode(request)), CreateStatementResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public CloseStatementResponse apply(CloseStatementRequest request) { - try { - return decode(apply(encode(request)), CloseStatementResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public OpenConnectionResponse apply(OpenConnectionRequest request) { - try { - return decode(apply(encode(request)), OpenConnectionResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public CloseConnectionResponse apply(CloseConnectionRequest request) { - try { - return decode(apply(encode(request)), CloseConnectionResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public ConnectionSyncResponse apply(ConnectionSyncRequest request) { - try { - return decode(apply(encode(request)), ConnectionSyncResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public DatabasePropertyResponse apply(DatabasePropertyRequest request) { - try { - return decode(apply(encode(request)), DatabasePropertyResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public SyncResultsResponse apply(SyncResultsRequest request) { - try { - return decode(apply(encode(request)), SyncResultsResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public CommitResponse apply(CommitRequest request) { - try { - return decode(apply(encode(request)), CommitResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public RollbackResponse apply(RollbackRequest request) { - try { - return decode(apply(encode(request)), RollbackResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public ExecuteBatchResponse apply(PrepareAndExecuteBatchRequest request) { - try { - return decode(apply(encode(request)), ExecuteBatchResponse.class); - } catch (IOException e) { - throw handle(e); - } - } - - public ExecuteBatchResponse apply(ExecuteBatchRequest request) { - try { - return decode(apply(encode(request)), ExecuteBatchResponse.class); - } catch (IOException e) { - throw handle(e); - } - } -} - -// End JsonService.java
