You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2015/12/02 19:06:09 UTC
[3/3] calcite git commit: [CALCITE-989] Add server's address in each
response
[CALCITE-989] Add server's address in each response
If the clients knows what server processed a response, the
client do perform their own load-balancing.
Fix some server Handler class hierarchy to make more sense
supporting both json and protobuf.
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/3be816f4
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/3be816f4
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/3be816f4
Branch: refs/heads/master
Commit: 3be816f450450e8e43286e6ea208af6e30520146
Parents: 81b4876
Author: Josh Elser <el...@apache.org>
Authored: Tue Nov 24 19:03:44 2015 -0500
Committer: Josh Elser <el...@apache.org>
Committed: Wed Dec 2 13:03:51 2015 -0500
----------------------------------------------------------------------
.../calcite/avatica/server/AvaticaHandler.java | 60 +-
.../avatica/server/AvaticaJsonHandler.java | 93 +
.../avatica/server/AvaticaProtobufHandler.java | 17 +-
.../server/DelegatingAvaticaHandler.java | 126 +
.../calcite/avatica/server/HandlerFactory.java | 2 +-
.../calcite/avatica/server/HttpServer.java | 47 +-
.../org/apache/calcite/avatica/server/Main.java | 2 +-
.../remote/AlternatingRemoteMetaTest.java | 4 +-
.../calcite/avatica/remote/RemoteMetaTest.java | 68 +-
.../avatica/server/HandlerFactoryTest.java | 2 +-
.../avatica/AvaticaClientRuntimeException.java | 10 +-
.../calcite/avatica/AvaticaSqlException.java | 12 +-
.../java/org/apache/calcite/avatica/Helper.java | 6 +-
.../apache/calcite/avatica/proto/Responses.java | 3110 +++++++++++++++++-
.../calcite/avatica/remote/AbstractHandler.java | 9 +-
.../calcite/avatica/remote/AbstractService.java | 14 +-
.../apache/calcite/avatica/remote/Handler.java | 9 +
.../calcite/avatica/remote/LocalService.java | 44 +-
.../avatica/remote/MockProtobufService.java | 12 +-
.../avatica/remote/ProtobufTranslationImpl.java | 4 +
.../apache/calcite/avatica/remote/Service.java | 506 ++-
avatica/src/main/protobuf/responses.proto | 21 +-
.../avatica/remote/ErrorResponseTest.java | 11 +-
.../avatica/remote/ProtobufHandlerTest.java | 4 +-
.../remote/ProtobufTranslationImplTest.java | 35 +-
.../test/AvaticaClientRuntimeExceptionTest.java | 5 +-
.../avatica/test/AvaticaSqlExceptionTest.java | 5 +-
.../calcite/avatica/test/JsonHandlerTest.java | 7 +-
28 files changed, 4001 insertions(+), 244 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
index f7c4800..d5501b9 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java
@@ -16,65 +16,15 @@
*/
package org.apache.calcite.avatica.server;
-import org.apache.calcite.avatica.AvaticaUtils;
-import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
-import org.apache.calcite.avatica.remote.JsonHandler;
-import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
-import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.ServletInputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.server.Handler;
/**
- * Jetty handler that executes Avatica JSON request-responses.
+ * A custom interface that extends the Jetty interface to enable extra control within Avatica.
*/
-public class AvaticaHandler extends AbstractHandler {
- private static final Log LOG = LogFactory.getLog(AvaticaHandler.class);
-
- final JsonHandler jsonHandler;
+public interface AvaticaHandler extends Handler {
- public AvaticaHandler(Service service) {
- this.jsonHandler = new JsonHandler(service);
- }
+ void setServerRpcMetadata(RpcMetadataResponse metadata);
- public void handle(String target, Request baseRequest,
- HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
- response.setContentType("application/json;charset=utf-8");
- response.setStatus(HttpServletResponse.SC_OK);
- if (request.getMethod().equals("POST")) {
- // First look for a request in the header, then look in the body.
- // The latter allows very large requests without hitting HTTP 413.
- String rawRequest = request.getHeader("request");
- if (rawRequest == null) {
- try (ServletInputStream inputStream = request.getInputStream()) {
- rawRequest = AvaticaUtils.readFully(inputStream);
- }
- }
- final String jsonRequest =
- new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
- if (LOG.isTraceEnabled()) {
- LOG.trace("request: " + jsonRequest);
- }
-
- final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
- if (LOG.isTraceEnabled()) {
- LOG.trace("response: " + jsonResponse);
- }
- baseRequest.setHandled(true);
- // Set the status code and write out the response.
- response.setStatus(jsonResponse.getStatusCode());
- response.getWriter().println(jsonResponse.getResponse());
- }
- }
}
-
-// End AvaticaHandler.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
new file mode 100644
index 0000000..106d53d
--- /dev/null
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
@@ -0,0 +1,93 @@
+/*
+ * 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.server;
+
+import org.apache.calcite.avatica.AvaticaUtils;
+import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
+import org.apache.calcite.avatica.remote.JsonHandler;
+import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Jetty handler that executes Avatica JSON request-responses.
+ */
+public class AvaticaJsonHandler extends AbstractHandler implements AvaticaHandler {
+ private static final Log LOG = LogFactory.getLog(AvaticaJsonHandler.class);
+
+ final Service service;
+ final JsonHandler jsonHandler;
+
+ public AvaticaJsonHandler(Service service) {
+ this.service = Objects.requireNonNull(service);
+ this.jsonHandler = new JsonHandler(service);
+ }
+
+ public void handle(String target, Request baseRequest,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ response.setContentType("application/json;charset=utf-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ if (request.getMethod().equals("POST")) {
+ // First look for a request in the header, then look in the body.
+ // The latter allows very large requests without hitting HTTP 413.
+ String rawRequest = request.getHeader("request");
+ if (rawRequest == null) {
+ try (ServletInputStream inputStream = request.getInputStream()) {
+ rawRequest = AvaticaUtils.readFully(inputStream);
+ }
+ }
+ final String jsonRequest =
+ new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("request: " + jsonRequest);
+ }
+
+ final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("response: " + jsonResponse);
+ }
+ baseRequest.setHandled(true);
+ // Set the status code and write out the response.
+ response.setStatus(jsonResponse.getStatusCode());
+ response.getWriter().println(jsonResponse.getResponse());
+ }
+ }
+
+ @Override
+ public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+ // Set the metadata for the normal service calls
+ service.setRpcMetadata(metadata);
+ // Also add it to the handler to include with exceptions
+ jsonHandler.setRpcMetadata(metadata);
+ }
+}
+
+// End AvaticaHandler.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
index 9dc6df0..bd4a8c9 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
@@ -22,6 +22,7 @@ import org.apache.calcite.avatica.remote.ProtobufHandler;
import org.apache.calcite.avatica.remote.ProtobufTranslation;
import org.apache.calcite.avatica.remote.ProtobufTranslationImpl;
import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -30,6 +31,8 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import java.io.IOException;
+import java.util.Objects;
+
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
@@ -38,14 +41,16 @@ import javax.servlet.http.HttpServletResponse;
/**
* Jetty handler that executes Avatica JSON request-responses.
*/
-public class AvaticaProtobufHandler extends AbstractHandler {
- private static final Log LOG = LogFactory.getLog(AvaticaHandler.class);
+public class AvaticaProtobufHandler extends AbstractHandler implements AvaticaHandler {
+ private static final Log LOG = LogFactory.getLog(AvaticaJsonHandler.class);
+ private final Service service;
private final ProtobufHandler pbHandler;
private final ProtobufTranslation protobufTranslation;
public AvaticaProtobufHandler(Service service) {
this.protobufTranslation = new ProtobufTranslationImpl();
+ this.service = Objects.requireNonNull(service);
this.pbHandler = new ProtobufHandler(service, protobufTranslation);
}
@@ -67,6 +72,14 @@ public class AvaticaProtobufHandler extends AbstractHandler {
response.getOutputStream().write(handlerResponse.getResponse());
}
}
+
+ @Override
+ public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+ // Set the metadata for the normal service calls
+ service.setRpcMetadata(metadata);
+ // Also add it to the handler to include with exceptions
+ pbHandler.setRpcMetadata(metadata);
+ }
}
// End AvaticaProtobufHandler.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
new file mode 100644
index 0000000..4b2457c
--- /dev/null
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
@@ -0,0 +1,126 @@
+/*
+ * 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.server;
+
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * An AvaticaHandler implementation which delegates to a provided Jetty Handler instance.
+ *
+ * This implementation provides a no-op implementation for
+ * {@link #setServerRpcMetadata(RpcMetadataResponse)}.
+ */
+public class DelegatingAvaticaHandler implements AvaticaHandler {
+ private static final Log LOG = LogFactory.getLog(DelegatingAvaticaHandler.class);
+
+ private final Handler handler;
+
+ public DelegatingAvaticaHandler(Handler handler) {
+ this.handler = Objects.requireNonNull(handler);
+ }
+
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ handler.handle(target, baseRequest, request, response);
+ }
+
+ @Override
+ public void setServer(Server server) {
+ handler.setServer(server);
+ }
+
+ @Override
+ public Server getServer() {
+ return handler.getServer();
+ }
+
+ @Override
+ public void destroy() {
+ handler.destroy();
+ }
+
+ @Override
+ public void start() throws Exception {
+ handler.start();
+ }
+
+ @Override
+ public void stop() throws Exception {
+ handler.stop();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return handler.isRunning();
+ }
+
+ @Override
+ public boolean isStarted() {
+ return handler.isStarted();
+ }
+
+ @Override
+ public boolean isStarting() {
+ return handler.isStarting();
+ }
+
+ @Override
+ public boolean isStopping() {
+ return handler.isStopping();
+ }
+
+ @Override
+ public boolean isStopped() {
+ return handler.isStopped();
+ }
+
+ @Override
+ public boolean isFailed() {
+ return handler.isFailed();
+ }
+
+ @Override
+ public void addLifeCycleListener(Listener listener) {
+ handler.addLifeCycleListener(listener);
+ }
+
+ @Override
+ public void removeLifeCycleListener(Listener listener) {
+ handler.removeLifeCycleListener(listener);
+ }
+
+ @Override
+ public void setServerRpcMetadata(RpcMetadataResponse metadata) {
+ LOG.warn("Setting RpcMetadata is not implemented for DelegatingAvaticaHandler");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
index c98f593..724626d 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
@@ -35,7 +35,7 @@ public class HandlerFactory {
public Handler getHandler(Service service, Driver.Serialization serialization) {
switch (serialization) {
case JSON:
- return new AvaticaHandler(service);
+ return new AvaticaJsonHandler(service);
case PROTOBUF:
return new AvaticaProtobufHandler(service);
default:
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
index 161a752..cffbf60 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java
@@ -16,6 +16,8 @@
*/
package org.apache.calcite.avatica.server;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,6 +29,9 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* Avatica HTTP server.
*
@@ -38,17 +43,35 @@ public class HttpServer {
private Server server;
private int port = -1;
- private final Handler handler;
+ private final AvaticaHandler handler;
+ @Deprecated
public HttpServer(Handler handler) {
+ this(wrapJettyHandler(handler));
+ }
+
+ public HttpServer(AvaticaHandler handler) {
this(0, handler);
}
+ @Deprecated
public HttpServer(int port, Handler handler) {
+ this(port, wrapJettyHandler(handler));
+ }
+
+ public HttpServer(int port, AvaticaHandler handler) {
this.port = port;
this.handler = handler;
}
+ private static AvaticaHandler wrapJettyHandler(Handler handler) {
+ if (handler instanceof AvaticaHandler) {
+ return (AvaticaHandler) handler;
+ }
+ // Backwards compatibility, noop's the AvaticaHandler interface
+ return new DelegatingAvaticaHandler(handler);
+ }
+
public void start() {
if (server != null) {
throw new RuntimeException("Server is already started");
@@ -74,6 +97,28 @@ public class HttpServer {
port = connector.getLocalPort();
LOG.info("Service listening on port " + getPort() + ".");
+
+ // Set the information about the address for this server
+ try {
+ this.handler.setServerRpcMetadata(createRpcServerMetadata(connector));
+ } catch (UnknownHostException e) {
+ // Failed to do the DNS lookup, bail out.
+ throw new RuntimeException(e);
+ }
+ }
+
+ private RpcMetadataResponse createRpcServerMetadata(ServerConnector connector) throws
+ UnknownHostException {
+ String host = connector.getHost();
+ if (null == host) {
+ // "null" means binding to all interfaces, we need to pick one so the client gets a real
+ // address and not "0.0.0.0" or similar.
+ host = InetAddress.getLocalHost().getHostName();
+ }
+
+ final int port = connector.getLocalPort();
+
+ return new RpcMetadataResponse(String.format("%s:%d", host, port));
}
/**
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
index 82691f6..8b05931 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/Main.java
@@ -46,7 +46,7 @@ public class Main {
private static final HandlerFactory JSON_HANDLER_FACTORY = new HandlerFactory() {
public AbstractHandler createHandler(Service service) {
- return new AvaticaHandler(service);
+ return new AvaticaJsonHandler(service);
}
};
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
index df2862d..ffd6f7c 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/AlternatingRemoteMetaTest.java
@@ -23,7 +23,7 @@ import org.apache.calcite.avatica.ConnectionPropertiesImpl;
import org.apache.calcite.avatica.ConnectionSpec;
import org.apache.calcite.avatica.Meta;
import org.apache.calcite.avatica.jdbc.JdbcMeta;
-import org.apache.calcite.avatica.server.AvaticaHandler;
+import org.apache.calcite.avatica.server.AvaticaJsonHandler;
import org.apache.calcite.avatica.server.HttpServer;
import org.apache.calcite.avatica.server.Main;
import org.apache.calcite.avatica.server.Main.HandlerFactory;
@@ -193,7 +193,7 @@ public class AlternatingRemoteMetaTest {
}
HttpServer jsonServer = Main.start(mainArgs, 0, new HandlerFactory() {
@Override public AbstractHandler createHandler(Service service) {
- return new AvaticaHandler(service);
+ return new AvaticaJsonHandler(service);
}
});
ACTIVE_SERVERS.add(jsonServer);
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 6cb4508..fbc91e6 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -24,7 +24,8 @@ import org.apache.calcite.avatica.ConnectionSpec;
import org.apache.calcite.avatica.Meta;
import org.apache.calcite.avatica.jdbc.JdbcMeta;
import org.apache.calcite.avatica.remote.Service.ErrorResponse;
-import org.apache.calcite.avatica.server.AvaticaHandler;
+import org.apache.calcite.avatica.remote.Service.Response;
+import org.apache.calcite.avatica.server.AvaticaJsonHandler;
import org.apache.calcite.avatica.server.AvaticaProtobufHandler;
import org.apache.calcite.avatica.server.HttpServer;
import org.apache.calcite.avatica.server.Main;
@@ -34,8 +35,6 @@ import org.apache.calcite.avatica.util.ArrayImpl;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Test;
@@ -45,6 +44,8 @@ import org.junit.runners.Parameterized.Parameters;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.Array;
import java.sql.Connection;
@@ -55,6 +56,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -66,6 +68,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -81,6 +84,8 @@ public class RemoteMetaTest {
private final HttpServer server;
private final String url;
+ private final int port;
+ private final Driver.Serialization serialization;
@Parameters
public static List<Object[]> parameters() throws Exception {
@@ -91,15 +96,15 @@ public class RemoteMetaTest {
// Bind to '0' to pluck an ephemeral port instead of expecting a certain one to be free
final HttpServer jsonServer = Main.start(mainArgs, 0, new HandlerFactory() {
- @Override public AbstractHandler createHandler(Service service) {
- return new AvaticaHandler(service);
+ @Override public AvaticaJsonHandler createHandler(Service service) {
+ return new AvaticaJsonHandler(service);
}
});
params.add(new Object[] {jsonServer, Driver.Serialization.JSON});
ACTIVE_SERVERS.add(jsonServer);
final HttpServer protobufServer = Main.start(mainArgs, 0, new HandlerFactory() {
- @Override public AbstractHandler createHandler(Service service) {
+ @Override public AvaticaProtobufHandler createHandler(Service service) {
return new AvaticaProtobufHandler(service);
}
});
@@ -112,7 +117,8 @@ public class RemoteMetaTest {
public RemoteMetaTest(HttpServer server, Driver.Serialization serialization) {
this.server = server;
- final int port = server.getPort();
+ this.port = this.server.getPort();
+ this.serialization = serialization;
url = "jdbc:avatica:remote:url=http://localhost:" + port + ";serialization="
+ serialization.name();
}
@@ -452,6 +458,54 @@ public class RemoteMetaTest {
}
}
+ @Test public void testServerAddressInResponse() throws Exception {
+ ConnectionSpec.getDatabaseLock().lock();
+ try {
+ URL url = new URL("http://localhost:" + this.port);
+ AvaticaHttpClient httpClient = new AvaticaHttpClientImpl(url);
+ byte[] request;
+
+ Service.OpenConnectionRequest jsonReq = new Service.OpenConnectionRequest(
+ UUID.randomUUID().toString(), Collections.<String, String>emptyMap());
+ switch (this.serialization) {
+ case JSON:
+ request = JsonService.MAPPER.writeValueAsBytes(jsonReq);
+ break;
+ case PROTOBUF:
+ ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
+ request = pbTranslation.serializeRequest(jsonReq);
+ break;
+ default:
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ byte[] response = httpClient.send(request);
+ Service.OpenConnectionResponse openCnxnResp;
+ switch (this.serialization) {
+ case JSON:
+ openCnxnResp = JsonService.MAPPER.readValue(response,
+ Service.OpenConnectionResponse.class);
+ break;
+ case PROTOBUF:
+ ProtobufTranslation pbTranslation = new ProtobufTranslationImpl();
+ Response genericResp = pbTranslation.parseResponse(response);
+ assertTrue("Expected an OpenConnnectionResponse, but got " + genericResp.getClass(),
+ genericResp instanceof Service.OpenConnectionResponse);
+ openCnxnResp = (Service.OpenConnectionResponse) genericResp;
+ break;
+ default:
+ throw new IllegalStateException("Should not reach here");
+ }
+
+ String hostname = InetAddress.getLocalHost().getHostName();
+
+ assertNotNull(openCnxnResp.rpcMetadata);
+ assertEquals(hostname + ":" + this.port, openCnxnResp.rpcMetadata.serverAddress);
+ } finally {
+ ConnectionSpec.getDatabaseLock().unlock();
+ }
+ }
+
/** Factory that provides a {@link JdbcMeta}. */
public static class FullyRemoteJdbcMetaFactory implements Meta.Factory {
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
index 13e9f7d..3504e02 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java
@@ -44,7 +44,7 @@ public class HandlerFactoryTest {
public void testJson() {
Handler handler = factory.getHandler(service, Serialization.JSON);
assertTrue("Expected an implementation of the AvaticaHandler, "
- + "but got " + handler.getClass(), handler instanceof AvaticaHandler);
+ + "but got " + handler.getClass(), handler instanceof AvaticaJsonHandler);
}
@Test
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
index 6859763..df03b03 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java
@@ -18,6 +18,7 @@ package org.apache.calcite.avatica;
import org.apache.calcite.avatica.remote.AvaticaRuntimeException;
import org.apache.calcite.avatica.remote.Service.ErrorResponse;
+import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse;
import java.util.Collections;
import java.util.List;
@@ -36,14 +37,16 @@ public class AvaticaClientRuntimeException extends RuntimeException {
private final String sqlState;
private final AvaticaSeverity severity;
private final List<String> serverExceptions;
+ private final RpcMetadataResponse metadata;
public AvaticaClientRuntimeException(String errorMessage, int errorCode, String sqlState,
- AvaticaSeverity severity, List<String> serverExceptions) {
+ AvaticaSeverity severity, List<String> serverExceptions, RpcMetadataResponse metadata) {
super(errorMessage);
this.errorCode = errorCode;
this.sqlState = sqlState;
this.severity = severity;
this.serverExceptions = serverExceptions;
+ this.metadata = metadata;
}
public AvaticaClientRuntimeException(String message, Throwable cause) {
@@ -52,6 +55,7 @@ public class AvaticaClientRuntimeException extends RuntimeException {
sqlState = ErrorResponse.UNKNOWN_SQL_STATE;
severity = AvaticaSeverity.UNKNOWN;
serverExceptions = Collections.singletonList("");
+ metadata = null;
}
public int getErrorCode() {
@@ -70,6 +74,10 @@ public class AvaticaClientRuntimeException extends RuntimeException {
return serverExceptions;
}
+ public RpcMetadataResponse getRpcMetadata() {
+ return metadata;
+ }
+
@Override public String toString() {
StringBuilder sb = new StringBuilder(64);
sb.append(getClass().getSimpleName()).append(": ")
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
index cfcf305..9408a7b 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaSqlException.java
@@ -31,6 +31,7 @@ public class AvaticaSqlException extends SQLException {
private final String errorMessage;
private final List<String> stackTraces;
+ private final String remoteServer;
/**
* Construct the Exception with information from the server.
@@ -38,12 +39,14 @@ public class AvaticaSqlException extends SQLException {
* @param errorMessage A human-readable error message.
* @param errorCode An integer corresponding to a known error.
* @param stackTraces Server-side stacktrace.
+ * @param remoteServer The host:port where the Avatica server is located
*/
public AvaticaSqlException(String errorMessage, String sqlState, int errorCode,
- List<String> stackTraces) {
+ List<String> stackTraces, String remoteServer) {
super("Error " + errorCode + " (" + sqlState + ") : " + errorMessage, sqlState, errorCode);
this.errorMessage = errorMessage;
this.stackTraces = Objects.requireNonNull(stackTraces);
+ this.remoteServer = remoteServer;
}
public String getErrorMessage() {
@@ -57,6 +60,13 @@ public class AvaticaSqlException extends SQLException {
return stackTraces;
}
+ /**
+ * @return The host:port for the remote Avatica server. May be null.
+ */
+ public String getRemoteServer() {
+ return remoteServer;
+ }
+
// printStackTrace() will get redirected to printStackTrace(PrintStream), don't need to override.
@Override public void printStackTrace(PrintStream stream) {
http://git-wip-us.apache.org/repos/asf/calcite/blob/3be816f4/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Helper.java b/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
index 54be099..27c6056 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Helper.java
@@ -46,8 +46,12 @@ public class Helper {
// The AvaticaClientRuntimeException contains extra information about what/why
// the exception was thrown that we can pass back to the user.
AvaticaClientRuntimeException rte = (AvaticaClientRuntimeException) e;
+ String serverAddress = null;
+ if (null != rte.getRpcMetadata()) {
+ serverAddress = rte.getRpcMetadata().serverAddress;
+ }
return new AvaticaSqlException(message, rte.getSqlState(), rte.getErrorCode(),
- rte.getServerExceptions());
+ rte.getServerExceptions(), serverAddress);
}
return new SQLException(message, e);
}