http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java deleted file mode 100644 index 17b33f8..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java +++ /dev/null @@ -1,215 +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.jdbc; - -import org.apache.calcite.avatica.AvaticaStatement; -import org.apache.calcite.avatica.Meta; -import org.apache.calcite.avatica.util.DateTimeUtils; - -import java.sql.Array; -import java.sql.Date; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Struct; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.TreeMap; - -/** Implementation of {@link org.apache.calcite.avatica.Meta.MetaResultSet} - * upon a JDBC {@link java.sql.ResultSet}. - * - * @see org.apache.calcite.avatica.jdbc.JdbcMeta */ -class JdbcResultSet extends Meta.MetaResultSet { - protected JdbcResultSet(String connectionId, int statementId, - boolean ownStatement, Meta.Signature signature, Meta.Frame firstFrame) { - this(connectionId, statementId, ownStatement, signature, firstFrame, -1L); - } - - protected JdbcResultSet(String connectionId, int statementId, - boolean ownStatement, Meta.Signature signature, Meta.Frame firstFrame, - long updateCount) { - super(connectionId, statementId, ownStatement, signature, firstFrame, updateCount); - } - - /** Creates a result set. */ - public static JdbcResultSet create(String connectionId, int statementId, - ResultSet resultSet) { - // -1 still limits to 100 but -2 does not limit to any number - return create(connectionId, statementId, resultSet, - JdbcMeta.UNLIMITED_COUNT); - } - - /** Creates a result set with maxRowCount. - * - * <p>If {@code maxRowCount} is -2 ({@link JdbcMeta#UNLIMITED_COUNT}), - * returns an unlimited number of rows in a single frame; any other - * negative value (typically -1) returns an unlimited number of rows - * in frames of the default frame size. */ - public static JdbcResultSet create(String connectionId, int statementId, - ResultSet resultSet, int maxRowCount) { - try { - Meta.Signature sig = JdbcMeta.signature(resultSet.getMetaData()); - return create(connectionId, statementId, resultSet, maxRowCount, sig); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - public static JdbcResultSet create(String connectionId, int statementId, - ResultSet resultSet, int maxRowCount, Meta.Signature signature) { - try { - final Calendar calendar = DateTimeUtils.calendar(); - final int fetchRowCount; - if (maxRowCount == JdbcMeta.UNLIMITED_COUNT) { - fetchRowCount = -1; - } else if (maxRowCount < 0L) { - fetchRowCount = AvaticaStatement.DEFAULT_FETCH_SIZE; - } else if (maxRowCount > AvaticaStatement.DEFAULT_FETCH_SIZE) { - fetchRowCount = AvaticaStatement.DEFAULT_FETCH_SIZE; - } else { - fetchRowCount = maxRowCount; - } - final Meta.Frame firstFrame = frame(null, resultSet, 0, fetchRowCount, calendar); - if (firstFrame.done) { - resultSet.close(); - } - return new JdbcResultSet(connectionId, statementId, true, signature, - firstFrame); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - /** Creates a empty result set with empty frame */ - public static JdbcResultSet empty(String connectionId, int statementId, - Meta.Signature signature) { - return new JdbcResultSet(connectionId, statementId, true, signature, - Meta.Frame.EMPTY); - } - - /** Creates a result set that only has an update count. */ - public static JdbcResultSet count(String connectionId, int statementId, - int updateCount) { - return new JdbcResultSet(connectionId, statementId, true, null, null, updateCount); - } - - /** Creates a frame containing a given number or unlimited number of rows - * from a result set. */ - static Meta.Frame frame(StatementInfo info, ResultSet resultSet, long offset, - int fetchMaxRowCount, Calendar calendar) throws SQLException { - final ResultSetMetaData metaData = resultSet.getMetaData(); - final int columnCount = metaData.getColumnCount(); - final int[] types = new int[columnCount]; - for (int i = 0; i < types.length; i++) { - types[i] = metaData.getColumnType(i + 1); - } - final List<Object> rows = new ArrayList<>(); - // Meta prepare/prepareAndExecute 0 return 0 row and done - boolean done = fetchMaxRowCount == 0; - for (int i = 0; fetchMaxRowCount < 0 || i < fetchMaxRowCount; i++) { - final boolean hasRow; - if (null != info) { - hasRow = info.next(); - } else { - hasRow = resultSet.next(); - } - if (!hasRow) { - done = true; - resultSet.close(); - break; - } - Object[] columns = new Object[columnCount]; - for (int j = 0; j < columnCount; j++) { - columns[j] = getValue(resultSet, types[j], j, calendar); - } - rows.add(columns); - } - return new Meta.Frame(offset, done, rows); - } - - private static Object getValue(ResultSet resultSet, int type, int j, - Calendar calendar) throws SQLException { - switch (type) { - case Types.BIGINT: - final long aLong = resultSet.getLong(j + 1); - return aLong == 0 && resultSet.wasNull() ? null : aLong; - case Types.INTEGER: - final int anInt = resultSet.getInt(j + 1); - return anInt == 0 && resultSet.wasNull() ? null : anInt; - case Types.SMALLINT: - final short aShort = resultSet.getShort(j + 1); - return aShort == 0 && resultSet.wasNull() ? null : aShort; - case Types.TINYINT: - final byte aByte = resultSet.getByte(j + 1); - return aByte == 0 && resultSet.wasNull() ? null : aByte; - case Types.DOUBLE: - case Types.FLOAT: - final double aDouble = resultSet.getDouble(j + 1); - return aDouble == 0D && resultSet.wasNull() ? null : aDouble; - case Types.REAL: - final float aFloat = resultSet.getFloat(j + 1); - return aFloat == 0D && resultSet.wasNull() ? null : aFloat; - case Types.DATE: - final Date aDate = resultSet.getDate(j + 1, calendar); - return aDate == null - ? null - : (int) (aDate.getTime() / DateTimeUtils.MILLIS_PER_DAY); - case Types.TIME: - final Time aTime = resultSet.getTime(j + 1, calendar); - return aTime == null - ? null - : (int) (aTime.getTime() % DateTimeUtils.MILLIS_PER_DAY); - case Types.TIMESTAMP: - final Timestamp aTimestamp = resultSet.getTimestamp(j + 1, calendar); - return aTimestamp == null ? null : aTimestamp.getTime(); - case Types.ARRAY: - final Array array = resultSet.getArray(j + 1); - if (null == array) { - return null; - } - ResultSet arrayValues = array.getResultSet(); - TreeMap<Integer, Object> map = new TreeMap<>(); - while (arrayValues.next()) { - // column 1 is the index in the array, column 2 is the value. - // Recurse on `getValue` to unwrap nested types correctly. - // `j` is zero-indexed and incremented for us, thus we have `1` being used twice. - map.put(arrayValues.getInt(1), getValue(arrayValues, array.getBaseType(), 1, calendar)); - } - // If the result set is not in the same order as the actual Array, TreeMap fixes that. - // Need to make a concrete list to ensure Jackson serialization. - //return new ListLike<Object>(new ArrayList<>(map.values()), ListLikeType.ARRAY); - return new ArrayList<>(map.values()); - case Types.STRUCT: - Struct struct = resultSet.getObject(j + 1, Struct.class); - Object[] attrs = struct.getAttributes(); - List<Object> list = new ArrayList<>(attrs.length); - for (Object o : attrs) { - list.add(o); - } - return list; - default: - return resultSet.getObject(j + 1); - } - } -} - -// End JdbcResultSet.java
http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/StatementInfo.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/StatementInfo.java b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/StatementInfo.java deleted file mode 100644 index c4f8e21..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/StatementInfo.java +++ /dev/null @@ -1,170 +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.jdbc; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.Statement; - -/** - * All we know about a statement. Encapsulates a {@link ResultSet}. - */ -public class StatementInfo { - private volatile Boolean relativeSupported = null; - - final Statement statement; // sometimes a PreparedStatement - private ResultSet resultSet; - private long position = 0; - - // True when setResultSet(ResultSet) is called to let us determine the difference between - // a null ResultSet (from an update) from the lack of a ResultSet. - private boolean resultsInitialized = false; - - public StatementInfo(Statement statement) { - // May be null when coming from a DatabaseMetaData call - this.statement = statement; - } - - // Visible for testing - void setPosition(long position) { - this.position = position; - } - - // Visible for testing - long getPosition() { - return this.position; - } - - /** - * Set a ResultSet on this object. - * - * @param resultSet The current ResultSet - */ - public void setResultSet(ResultSet resultSet) { - resultsInitialized = true; - this.resultSet = resultSet; - } - - /** - * @return The {@link ResultSet} for this Statement, may be null. - */ - public ResultSet getResultSet() { - return this.resultSet; - } - - /** - * @return True if {@link #setResultSet(ResultSet)} was ever invoked. - */ - public boolean isResultSetInitialized() { - return resultsInitialized; - } - - /** - * @see ResultSet#next() - */ - public boolean next() throws SQLException { - return _next(resultSet); - } - - boolean _next(ResultSet results) throws SQLException { - boolean ret = results.next(); - position++; - return ret; - } - - /** - * Consumes <code>offset - position</code> elements from the {@link ResultSet}. - * - * @param offset The offset to advance to - * @return True if the resultSet was advanced to the current point, false if insufficient rows - * were present to advance to the requested offset. - */ - public boolean advanceResultSetToOffset(ResultSet results, long offset) throws SQLException { - if (offset < 0 || offset < position) { - throw new IllegalArgumentException("Offset should be " - + " non-negative and not less than the current position. " + offset + ", " + position); - } - if (position >= offset) { - return true; - } - - if (null == relativeSupported) { - Boolean moreResults = null; - synchronized (this) { - if (null == relativeSupported) { - try { - moreResults = advanceByRelative(results, offset); - relativeSupported = true; - } catch (SQLFeatureNotSupportedException e) { - relativeSupported = false; - } - } - } - - if (null != moreResults) { - // We figured out whether or not relative is supported. - // Make sure we actually do the necessary work. - if (!relativeSupported) { - // We avoided calling advanceByNext in the synchronized block earlier. - moreResults = advanceByNext(results, offset); - } - - return moreResults; - } - - // Another thread updated the RELATIVE_SUPPORTED before we did, fall through. - } - - if (relativeSupported) { - return advanceByRelative(results, offset); - } else { - return advanceByNext(results, offset); - } - } - - private boolean advanceByRelative(ResultSet results, long offset) throws SQLException { - long diff = offset - position; - while (diff > Integer.MAX_VALUE) { - if (!results.relative(Integer.MAX_VALUE)) { - // Avoid updating position until relative succeeds. - position += Integer.MAX_VALUE; - return false; - } - // Avoid updating position until relative succeeds. - position += Integer.MAX_VALUE; - diff -= Integer.MAX_VALUE; - } - boolean ret = results.relative((int) diff); - // Make sure we only update the position after successfully calling relative(int). - position += diff; - return ret; - } - - private boolean advanceByNext(ResultSet results, long offset) throws SQLException { - while (position < offset) { - // Advance while maintaining `position` - if (!_next(results)) { - return false; - } - } - - return true; - } -} - -// End StatementInfo.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java b/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java deleted file mode 100644 index 8b8fb76..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java +++ /dev/null @@ -1,22 +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. - */ - -/** Implements an Avatica provider on top of an existing JDBC data source. */ -package org.apache.calcite.avatica.jdbc; - - -// End package-info.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/server/AbstractAvaticaHandler.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AbstractAvaticaHandler.java b/avatica/server/src/main/java/org/apache/calcite/avatica/server/AbstractAvaticaHandler.java deleted file mode 100644 index 3a7ccf3..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AbstractAvaticaHandler.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.server; - -import org.apache.calcite.avatica.AvaticaSeverity; -import org.apache.calcite.avatica.remote.AuthenticationType; -import org.apache.calcite.avatica.remote.Service.ErrorResponse; - -import org.eclipse.jetty.server.handler.AbstractHandler; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.util.Collections; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Base-class for Avatica implemented Jetty Handlers. - */ -public abstract class AbstractAvaticaHandler extends AbstractHandler - implements MetricsAwareAvaticaHandler { - - private static final ErrorResponse UNAUTHORIZED_ERROR = new ErrorResponse( - Collections.<String>emptyList(), "User is not authenticated", - ErrorResponse.UNAUTHORIZED_ERROR_CODE, ErrorResponse.UNAUTHORIZED_SQL_STATE, - AvaticaSeverity.ERROR, null); - - /** - * Determines if a request is permitted to be executed. The server may require authentication - * and the login mechanism might have failed. This check verifies that only authenticated - * users are permitted through when the server is requiring authentication. When a user - * is disallowed, a status code and response will be automatically written to the provided - * <code>response</code> and the caller should return immediately. - * - * @param serverConfig The server's configuration - * @param request The user's request - * @param response The response to the user's request - * @return True if request can proceed, false otherwise. - */ - public boolean isUserPermitted(AvaticaServerConfiguration serverConfig, - HttpServletRequest request, HttpServletResponse response) throws IOException { - // Make sure that we drop any unauthenticated users out first. - if (null != serverConfig) { - if (AuthenticationType.SPNEGO == serverConfig.getAuthenticationType()) { - String remoteUser = request.getRemoteUser(); - if (null == remoteUser) { - response.setStatus(HttpURLConnection.HTTP_UNAUTHORIZED); - response.getOutputStream().write(UNAUTHORIZED_ERROR.serialize().toByteArray()); - return false; - } - } - } - - return true; - } -} - -// End AbstractAvaticaHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index 42b13c9..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaHandler.java +++ /dev/null @@ -1,32 +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.server; - -import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; - -import org.eclipse.jetty.server.Handler; - -/** - * A custom interface that extends the Jetty interface to enable extra control within Avatica. - */ -public interface AvaticaHandler extends Handler { - - void setServerRpcMetadata(RpcMetadataResponse metadata); - -} - -// End AvaticaHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index b639183..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java +++ /dev/null @@ -1,157 +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.server; - -import org.apache.calcite.avatica.AvaticaUtils; -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.metrics.noop.NoopMetricsSystem; -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.calcite.avatica.util.UnsynchronizedBuffer; - -import org.eclipse.jetty.server.Request; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.Callable; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import static org.apache.calcite.avatica.remote.MetricsHelper.concat; - -/** - * Jetty handler that executes Avatica JSON request-responses. - */ -public class AvaticaJsonHandler extends AbstractAvaticaHandler { - private static final Logger LOG = LoggerFactory.getLogger(AvaticaJsonHandler.class); - - final Service service; - final JsonHandler jsonHandler; - - final MetricsSystem metrics; - final Timer requestTimer; - - final ThreadLocal<UnsynchronizedBuffer> threadLocalBuffer; - - final AvaticaServerConfiguration serverConfig; - - public AvaticaJsonHandler(Service service) { - this(service, NoopMetricsSystem.getInstance(), null); - } - - public AvaticaJsonHandler(Service service, MetricsSystem metrics) { - this(service, metrics, null); - } - - public AvaticaJsonHandler(Service service, MetricsSystem metrics, - AvaticaServerConfiguration serverConfig) { - this.service = Objects.requireNonNull(service); - this.metrics = Objects.requireNonNull(metrics); - // Avatica doesn't have a Guava dependency - this.jsonHandler = new JsonHandler(service, this.metrics); - - // Metrics - this.requestTimer = this.metrics.getTimer( - concat(AvaticaJsonHandler.class, MetricsAwareAvaticaHandler.REQUEST_TIMER_NAME)); - - this.threadLocalBuffer = new ThreadLocal<UnsynchronizedBuffer>() { - @Override public UnsynchronizedBuffer initialValue() { - return new UnsynchronizedBuffer(); - } - }; - - this.serverConfig = serverConfig; - } - - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - try (final Context ctx = requestTimer.start()) { - if (!isUserPermitted(serverConfig, request, response)) { - LOG.debug("HTTP request from {} is unauthenticated and authentication is required", - request.getRemoteAddr()); - return; - } - - 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) { - // Avoid a new buffer creation for every HTTP request - final UnsynchronizedBuffer buffer = threadLocalBuffer.get(); - try (ServletInputStream inputStream = request.getInputStream()) { - rawRequest = AvaticaUtils.readFully(inputStream, buffer); - } finally { - // Reset the offset into the buffer after we're done - buffer.reset(); - } - } - final String jsonRequest = - new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8"); - LOG.trace("request: {}", jsonRequest); - - HandlerResponse<String> jsonResponse; - try { - if (null != serverConfig && serverConfig.supportsImpersonation()) { - jsonResponse = serverConfig.doAsRemoteUser(request.getRemoteUser(), - request.getRemoteAddr(), new Callable<HandlerResponse<String>>() { - @Override public HandlerResponse<String> call() { - return jsonHandler.apply(jsonRequest); - } - }); - } else { - jsonResponse = jsonHandler.apply(jsonRequest); - } - } catch (Exception e) { - LOG.debug("Error invoking request from {}", baseRequest.getRemoteAddr(), e); - jsonResponse = jsonHandler.convertToErrorResponse(e); - } - - 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); - } - - @Override public MetricsSystem getMetrics() { - return metrics; - } -} - -// End AvaticaJsonHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index f8723f1..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java +++ /dev/null @@ -1,152 +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.server; - -import org.apache.calcite.avatica.AvaticaUtils; -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.metrics.noop.NoopMetricsSystem; -import org.apache.calcite.avatica.remote.Handler.HandlerResponse; -import org.apache.calcite.avatica.remote.MetricsHelper; -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.calcite.avatica.util.UnsynchronizedBuffer; - -import org.eclipse.jetty.server.Request; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.Callable; - -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 AvaticaProtobufHandler extends AbstractAvaticaHandler { - private static final Logger LOG = LoggerFactory.getLogger(AvaticaJsonHandler.class); - - private final Service service; - private final ProtobufHandler pbHandler; - private final ProtobufTranslation protobufTranslation; - private final MetricsSystem metrics; - private final Timer requestTimer; - private final AvaticaServerConfiguration serverConfig; - - final ThreadLocal<UnsynchronizedBuffer> threadLocalBuffer; - - public AvaticaProtobufHandler(Service service) { - this(service, NoopMetricsSystem.getInstance()); - } - - public AvaticaProtobufHandler(Service service, MetricsSystem metrics) { - this(service, metrics, null); - } - - public AvaticaProtobufHandler(Service service, MetricsSystem metrics, - AvaticaServerConfiguration serverConfig) { - this.service = Objects.requireNonNull(service); - this.metrics = Objects.requireNonNull(metrics); - - this.requestTimer = this.metrics.getTimer( - MetricsHelper.concat(AvaticaProtobufHandler.class, - MetricsAwareAvaticaHandler.REQUEST_TIMER_NAME)); - - this.protobufTranslation = new ProtobufTranslationImpl(); - this.pbHandler = new ProtobufHandler(service, protobufTranslation, metrics); - - this.threadLocalBuffer = new ThreadLocal<UnsynchronizedBuffer>() { - @Override public UnsynchronizedBuffer initialValue() { - return new UnsynchronizedBuffer(); - } - }; - - this.serverConfig = serverConfig; - } - - public void handle(String target, Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - try (final Context ctx = this.requestTimer.start()) { - // Check if the user is OK to proceed. - if (!isUserPermitted(serverConfig, request, response)) { - LOG.debug("HTTP request from {} is unauthenticated and authentication is required", - request.getRemoteAddr()); - return; - } - - response.setContentType("application/octet-stream;charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - if (request.getMethod().equals("POST")) { - final byte[] requestBytes; - // Avoid a new buffer creation for every HTTP request - final UnsynchronizedBuffer buffer = threadLocalBuffer.get(); - try (ServletInputStream inputStream = request.getInputStream()) { - requestBytes = AvaticaUtils.readFullyToBytes(inputStream, buffer); - } finally { - buffer.reset(); - } - - HandlerResponse<byte[]> handlerResponse; - try { - if (null != serverConfig && serverConfig.supportsImpersonation()) { - // Invoke the ProtobufHandler inside as doAs for the remote user. - handlerResponse = serverConfig.doAsRemoteUser(request.getRemoteUser(), - request.getRemoteAddr(), new Callable<HandlerResponse<byte[]>>() { - @Override public HandlerResponse<byte[]> call() { - return pbHandler.apply(requestBytes); - } - }); - } else { - handlerResponse = pbHandler.apply(requestBytes); - } - } catch (Exception e) { - LOG.debug("Error invoking request from {}", baseRequest.getRemoteAddr(), e); - // Catch at the highest level of exceptions - handlerResponse = pbHandler.convertToErrorResponse(e); - } - - baseRequest.setHandled(true); - response.setStatus(handlerResponse.getStatusCode()); - 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); - } - - @Override public MetricsSystem getMetrics() { - return this.metrics; - } - -} - -// End AvaticaProtobufHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaServerConfiguration.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaServerConfiguration.java b/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaServerConfiguration.java deleted file mode 100644 index dd843a4..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/AvaticaServerConfiguration.java +++ /dev/null @@ -1,97 +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.server; - -import org.apache.calcite.avatica.remote.AuthenticationType; - -import java.util.concurrent.Callable; - -/** - * A generic configuration interface that users can implement to configure the {@link HttpServer}. - */ -public interface AvaticaServerConfiguration { - - /** - * Returns the type of authentication the {@link HttpServer} should use. - * @return An enum corresponding to an authentication mechanism - */ - AuthenticationType getAuthenticationType(); - - /** - * Returns the Kerberos realm to use for the server's login. Only relevant when - * {@link #getAuthenticationType()} returns {@link AuthenticationType#SPNEGO}. - * - * @return The Kerberos realm for the server login, or null if not applicable. - */ - String getKerberosRealm(); - - /** - * Returns the Kerberos principal that the Avatica server should log in as. - * - * @return A Kerberos principal, or null if not applicable. - */ - String getKerberosPrincipal(); - - /** - * Returns the array of allowed roles for login. Only applicable when - * {@link #getAuthenticationType()} returns {@link AuthenticationType#BASIC} or - * {@link AuthenticationType#DIGEST}. - * - * @return An array of allowed login roles, or null. - */ - String[] getAllowedRoles(); - - /** - * Returns the name of the realm to use in coordination with the properties files specified - * by {@link #getHashLoginServiceProperties()}. Only applicable when - * {@link #getAuthenticationType()} returns {@link AuthenticationType#BASIC} or - * {@link AuthenticationType#DIGEST}. - * - * @return A realm for the HashLoginService, or null. - */ - String getHashLoginServiceRealm(); - - /** - * Returns the path to a properties file that contains users and realms. Only applicable when - * {@link #getAuthenticationType()} returns {@link AuthenticationType#BASIC} or - * {@link AuthenticationType#DIGEST}. - * - * @return A realm for the HashLoginService, or null. - */ - String getHashLoginServiceProperties(); - - /** - * Returns true if the Avatica server should run user requests at that remote user. Otherwise, - * all requests are run as the Avatica server user (which is the default). - * - * @return True if impersonation is enabled, false otherwise. - */ - boolean supportsImpersonation(); - - /** - * Invokes the given <code>action</code> as the <code>remoteUserName</code>. This will only be - * invoked if {@link #supportsImpersonation()} returns <code>true</code>. - * - * @param remoteUserName The remote user making a request to the Avatica server. - * @param remoteAddress The address the remote user is making the request from. - * @return The result from the Callable. - */ - <T> T doAsRemoteUser(String remoteUserName, String remoteAddress, Callable<T> action) - throws Exception; -} - -// End AvaticaServerConfiguration.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index fff176d..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java +++ /dev/null @@ -1,116 +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.server; - -import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; - -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -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 that delegates to a provided Jetty Handler instance. - * - * <p>This implementation provides a no-op implementation for - * {@link #setServerRpcMetadata(org.apache.calcite.avatica.remote.Service.RpcMetadataResponse)}. - * - * <p>Does not implement {@link MetricsAwareAvaticaHandler} as this implementation is only presented - * for backwards compatibility. - */ -public class DelegatingAvaticaHandler implements AvaticaHandler { - private static final Logger LOG = LoggerFactory.getLogger(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"); - } - -} - -// End DelegatingAvaticaHandler.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/avatica/server/src/main/java/org/apache/calcite/avatica/server/DoAsRemoteUserCallback.java ---------------------------------------------------------------------- diff --git a/avatica/server/src/main/java/org/apache/calcite/avatica/server/DoAsRemoteUserCallback.java b/avatica/server/src/main/java/org/apache/calcite/avatica/server/DoAsRemoteUserCallback.java deleted file mode 100644 index c2be80f..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/DoAsRemoteUserCallback.java +++ /dev/null @@ -1,42 +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.server; - -import java.util.concurrent.Callable; - -/** - * A callback which the server can invoke to allow implementations to control additional logic - * about whether or not a client from a specific host should be run. - * <p>For example, complex logic could be supplied to control whether clientA from host1 is - * permitted to execute queries. This logic is deferred upon the user to implement. - */ -public interface DoAsRemoteUserCallback { - - /** - * Invokes the given <code>action</code> as the <code>remoteUserName</code>. - * - * @param remoteUserName The remote user making a request to the Avatica server. - * @param remoteAddress The address the remote user is making the request from. - * @param action The operation the Avatica server wants to run as <code>remoteUserName</code>. - * @return The result from the Callable. - */ - <T> T doAsRemoteUser(String remoteUserName, String remoteAddress, Callable<T> action) - throws Exception; - -} - -// End DoAsRemoteUserCallback.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index 6c70d1b..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java +++ /dev/null @@ -1,146 +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.server; - -import org.apache.calcite.avatica.metrics.MetricsSystem; -import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration; -import org.apache.calcite.avatica.metrics.MetricsSystemFactory; -import org.apache.calcite.avatica.metrics.MetricsSystemLoader; -import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem; -import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystemConfiguration; -import org.apache.calcite.avatica.remote.Driver; -import org.apache.calcite.avatica.remote.Service; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.ServiceLoader; - -/** - * Factory that instantiates the desired implementation, typically differing on the method - * used to serialize messages, for use in the Avatica server. - */ -public class HandlerFactory { - private static final Logger LOG = LoggerFactory.getLogger(HandlerFactory.class); - - /** - * Constructs the desired implementation for the given serialization method with metrics. - * - * @param service The underlying {@link Service}. - * @param serialization The desired message serialization. - * @return The {@link AvaticaHandler}. - */ - public AvaticaHandler getHandler(Service service, Driver.Serialization serialization) { - return getHandler(service, serialization, NoopMetricsSystemConfiguration.getInstance()); - } - - /** - * Constructs the desired implementation for the given serialization method and server - * configuration with metrics. - * - * @param service The underlying {@link Service}. - * @param serialization The desired message serialization. - * @param serverConfig Avatica server configuration or null. - * @return The {@link AvaticaHandler}. - */ - public AvaticaHandler getHandler(Service service, Driver.Serialization serialization, - AvaticaServerConfiguration serverConfig) { - return getHandler(service, serialization, NoopMetricsSystemConfiguration.getInstance(), - serverConfig); - } - - /** - * Constructs the desired implementation for the given serialization method with metrics. - * - * @param service The underlying {@link Service}. - * @param serialization The desired message serialization. - * @param metricsConfig Configuration for the {@link MetricsSystem}. - * @return The {@link AvaticaHandler}. - */ - public AvaticaHandler getHandler(Service service, Driver.Serialization serialization, - MetricsSystemConfiguration<?> metricsConfig) { - return getHandler(service, serialization, metricsConfig, null); - } - - /** - * Constructs the desired implementation for the given serialization method and server - * configuration with metrics. - * - * @param service The underlying {@link Service} - * @param serialization The serializatio mechanism to use - * @param metricsConfig Configuration for the {@link MetricsSystem}. - * @param serverConfig Avatica server configuration or null - * @return An {@link AvaticaHandler} - */ - public AvaticaHandler getHandler(Service service, Driver.Serialization serialization, - MetricsSystemConfiguration<?> metricsConfig, AvaticaServerConfiguration serverConfig) { - if (null == metricsConfig) { - metricsConfig = NoopMetricsSystemConfiguration.getInstance(); - } - MetricsSystem metrics = MetricsSystemLoader.load(metricsConfig); - - switch (serialization) { - case JSON: - return new AvaticaJsonHandler(service, metrics, serverConfig); - case PROTOBUF: - return new AvaticaProtobufHandler(service, metrics, serverConfig); - default: - throw new IllegalArgumentException("Unknown Avatica handler for " + serialization.name()); - } - } - - /** - * Load a {@link MetricsSystem} using ServiceLoader to create a {@link MetricsSystemFactory}. - * - * @param config State to pass to the factory for initialization. - * @return A {@link MetricsSystem} instance. - */ - MetricsSystem loadMetricsSystem(MetricsSystemConfiguration<?> config) { - ServiceLoader<MetricsSystemFactory> loader = ServiceLoader.load(MetricsSystemFactory.class); - List<MetricsSystemFactory> availableFactories = new ArrayList<>(); - for (MetricsSystemFactory factory : loader) { - availableFactories.add(factory); - } - - if (1 == availableFactories.size()) { - // One and only one instance -- what we want - MetricsSystemFactory factory = availableFactories.get(0); - LOG.info("Loaded MetricsSystem {}", factory.getClass()); - return factory.create(config); - } else if (availableFactories.isEmpty()) { - // None-provided default to no metrics - LOG.info("No metrics implementation available on classpath. Using No-op implementation"); - return NoopMetricsSystem.getInstance(); - } else { - // Tell the user they're doing something wrong, and choose the first impl. - StringBuilder sb = new StringBuilder(); - for (MetricsSystemFactory factory : availableFactories) { - if (sb.length() > 0) { - sb.append(", "); - } - sb.append(factory.getClass()); - } - LOG.warn("Found multiple MetricsSystemFactory implementations: {}." - + " Using No-op implementation", sb); - return NoopMetricsSystem.getInstance(); - } - } -} - -// End HandlerFactory.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index 4c871f0..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java +++ /dev/null @@ -1,826 +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.server; - -import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration; -import org.apache.calcite.avatica.remote.AuthenticationType; -import org.apache.calcite.avatica.remote.Driver.Serialization; -import org.apache.calcite.avatica.remote.Service; -import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; - -import org.eclipse.jetty.security.Authenticator; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; -import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.security.authentication.DigestAuthenticator; -import org.eclipse.jetty.security.authentication.SpnegoAuthenticator; -import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.DefaultHandler; -import org.eclipse.jetty.server.handler.HandlerList; -import org.eclipse.jetty.util.security.Constraint; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.util.thread.QueuedThreadPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.Principal; -import java.security.PrivilegedAction; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.Callable; - -import javax.security.auth.Subject; -import javax.security.auth.kerberos.KerberosPrincipal; -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -/** - * Avatica HTTP server. - * - * <p>If you need to change the server's configuration, override the - * {@link #configureConnector(ServerConnector, int)} method in a derived class. - */ -public class HttpServer { - private static final Logger LOG = LoggerFactory.getLogger(HttpServer.class); - - private Server server; - private int port = -1; - private final AvaticaHandler handler; - private final AvaticaServerConfiguration config; - private final Subject subject; - private final SslContextFactory sslFactory; - - @Deprecated - public HttpServer(Handler handler) { - this(wrapJettyHandler(handler)); - } - - /** - * Constructs an {@link HttpServer} which binds to an ephemeral port. - * @param handler The Handler to run - */ - public HttpServer(AvaticaHandler handler) { - this(0, handler); - } - - @Deprecated - public HttpServer(int port, Handler handler) { - this(port, wrapJettyHandler(handler)); - } - - /** - * Constructs an {@link HttpServer} with no additional configuration. - * @param port The listen port - * @param handler The Handler to run - */ - public HttpServer(int port, AvaticaHandler handler) { - this(port, handler, null); - } - - /** - * Constructs an {@link HttpServer}. - * @param port The listen port - * @param handler The Handler to run - * @param config Optional configuration for the server - */ - public HttpServer(int port, AvaticaHandler handler, AvaticaServerConfiguration config) { - this(port, handler, config, null); - } - - /** - * Constructs an {@link HttpServer}. - * @param port The listen port - * @param handler The Handler to run - * @param config Optional configuration for the server - * @param subject The javax.security Subject for the server, or null - */ - public HttpServer(int port, AvaticaHandler handler, AvaticaServerConfiguration config, - Subject subject) { - this(port, handler, config, subject, null); - } - - /** - * Constructs an {@link HttpServer}. - * @param port The listen port - * @param handler The Handler to run - * @param config Optional configuration for the server - * @param subject The javax.security Subject for the server, or null - * @param sslFactory A configured SslContextFactory, or null - */ - public HttpServer(int port, AvaticaHandler handler, AvaticaServerConfiguration config, - Subject subject, SslContextFactory sslFactory) { - this.port = port; - this.handler = handler; - this.config = config; - this.subject = subject; - this.sslFactory = sslFactory; - } - - 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 (null != subject) { - // Run the start in the privileged block (as the kerberos-identified user) - Subject.doAs(subject, new PrivilegedAction<Void>() { - @Override public Void run() { - internalStart(); - return null; - } - }); - } else { - internalStart(); - } - } - - protected void internalStart() { - if (server != null) { - throw new RuntimeException("Server is already started"); - } - - final QueuedThreadPool threadPool = new QueuedThreadPool(); - threadPool.setDaemon(true); - server = new Server(threadPool); - server.manage(threadPool); - - final ServerConnector connector = configureConnector(getConnector(), port); - ConstraintSecurityHandler securityHandler = null; - - if (null != this.config) { - switch (config.getAuthenticationType()) { - case SPNEGO: - // Get the Handler for SPNEGO authentication - securityHandler = configureSpnego(server, connector, this.config); - break; - case BASIC: - securityHandler = configureBasicAuthentication(server, connector, config); - break; - case DIGEST: - securityHandler = configureDigestAuthentication(server, connector, config); - break; - default: - // Pass - break; - } - } - - server.setConnectors(new Connector[] { connector }); - - // Default to using the handler that was passed in - final HandlerList handlerList = new HandlerList(); - Handler avaticaHandler = handler; - - // Wrap the provided handler for security if we made one - if (null != securityHandler) { - securityHandler.setHandler(handler); - avaticaHandler = securityHandler; - } - - handlerList.setHandlers(new Handler[] {avaticaHandler, new DefaultHandler()}); - - server.setHandler(handlerList); - try { - server.start(); - } catch (Exception e) { - throw new RuntimeException(e); - } - 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 ServerConnector getConnector() { - if (null == sslFactory) { - return new ServerConnector(server); - } - return new ServerConnector(server, sslFactory); - } - - 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(Locale.ROOT, "%s:%d", host, port)); - } - - /** - * Configures the <code>connector</code> given the <code>config</code> for using SPNEGO. - * - * @param connector The connector to configure - * @param config The configuration - */ - protected ConstraintSecurityHandler configureSpnego(Server server, ServerConnector connector, - AvaticaServerConfiguration config) { - final String realm = Objects.requireNonNull(config.getKerberosRealm()); - final String principal = Objects.requireNonNull(config.getKerberosPrincipal()); - - // A customization of SpnegoLoginService to explicitly set the server's principal, otherwise - // we would have to require a custom file to set the server's principal. - PropertyBasedSpnegoLoginService spnegoLoginService = - new PropertyBasedSpnegoLoginService(realm, principal); - - // Roles are "realms" for Kerberos/SPNEGO - final String[] allowedRealms = getAllowedRealms(realm, config); - - return configureCommonAuthentication(server, connector, config, Constraint.__SPNEGO_AUTH, - allowedRealms, new SpnegoAuthenticator(), realm, spnegoLoginService); - } - - protected String[] getAllowedRealms(String serverRealm, AvaticaServerConfiguration config) { - // Roles are "realms" for Kerberos/SPNEGO - String[] allowedRealms = new String[] {serverRealm}; - // By default, only the server's realm is allowed, but other realms can also be allowed. - if (null != config.getAllowedRoles()) { - allowedRealms = new String[config.getAllowedRoles().length + 1]; - allowedRealms[0] = serverRealm; - System.arraycopy(config.getAllowedRoles(), 0, allowedRealms, 1, - config.getAllowedRoles().length); - } - return allowedRealms; - } - - protected ConstraintSecurityHandler configureBasicAuthentication(Server server, - ServerConnector connector, AvaticaServerConfiguration config) { - final String[] allowedRoles = config.getAllowedRoles(); - final String realm = config.getHashLoginServiceRealm(); - final String loginServiceProperties = config.getHashLoginServiceProperties(); - - HashLoginService loginService = new HashLoginService(realm, loginServiceProperties); - server.addBean(loginService); - - return configureCommonAuthentication(server, connector, config, Constraint.__BASIC_AUTH, - allowedRoles, new BasicAuthenticator(), null, loginService); - } - - protected ConstraintSecurityHandler configureDigestAuthentication(Server server, - ServerConnector connector, AvaticaServerConfiguration config) { - final String[] allowedRoles = config.getAllowedRoles(); - final String realm = config.getHashLoginServiceRealm(); - final String loginServiceProperties = config.getHashLoginServiceProperties(); - - HashLoginService loginService = new HashLoginService(realm, loginServiceProperties); - server.addBean(loginService); - - return configureCommonAuthentication(server, connector, config, Constraint.__DIGEST_AUTH, - allowedRoles, new DigestAuthenticator(), null, loginService); - } - - protected ConstraintSecurityHandler configureCommonAuthentication(Server server, - ServerConnector connector, AvaticaServerConfiguration config, String constraintName, - String[] allowedRoles, Authenticator authenticator, String realm, - LoginService loginService) { - - Constraint constraint = new Constraint(); - constraint.setName(constraintName); - constraint.setRoles(allowedRoles); - // This is telling Jetty to not allow unauthenticated requests through (very important!) - constraint.setAuthenticate(true); - - ConstraintMapping cm = new ConstraintMapping(); - cm.setConstraint(constraint); - cm.setPathSpec("/*"); - - ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); - sh.setAuthenticator(authenticator); - sh.setLoginService(loginService); - sh.setConstraintMappings(new ConstraintMapping[]{cm}); - sh.setRealmName(realm); - - return sh; - } - - /** - * Configures the server connector. - * - * <p>The default configuration sets a timeout of 1 minute and disables - * TCP linger time. - * - * <p>To change the configuration, override this method in a derived class. - * The overriding method must call its super method. - * - * @param connector connector to be configured - * @param port port number handed over in constructor - */ - protected ServerConnector configureConnector(ServerConnector connector, int port) { - connector.setIdleTimeout(60 * 1000); - connector.setSoLingerTime(-1); - connector.setPort(port); - return connector; - } - - protected AvaticaServerConfiguration getConfig() { - return this.config; - } - - public void stop() { - if (server == null) { - throw new RuntimeException("Server is already stopped"); - } - - LOG.info("Service terminating."); - try { - final Server server1 = server; - port = -1; - server = null; - server1.stop(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public void join() throws InterruptedException { - server.join(); - } - - public int getPort() { - return port; - } - - /** - * Builder class for creating instances of {@link HttpServer}. - */ - public static class Builder { - private int port; - - private Service service; - private Serialization serialization; - private AvaticaHandler handler = null; - - private MetricsSystemConfiguration<?> metricsConfig; - - private AuthenticationType authenticationType = AuthenticationType.NONE; - - private String kerberosPrincipal; - private String kerberosRealm; - private File keytab; - - private DoAsRemoteUserCallback remoteUserCallback; - - private String loginServiceRealm; - private String loginServiceProperties; - private String[] loginServiceAllowedRoles; - - private boolean usingTLS = false; - private File keystore; - private String keystorePassword; - private File truststore; - private String truststorePassword; - - public Builder() {} - - public Builder withPort(int port) { - this.port = port; - return this; - } - - /** - * Sets the {@link Service} and {@link Serialization} information necessary to construct - * the appropriate {@link AvaticaHandler}. - * - * @param service The Avatica service - * @param serialization The serialization method - * @return <code>this</code> - */ - public Builder withHandler(Service service, Serialization serialization) { - this.service = Objects.requireNonNull(service); - this.serialization = Objects.requireNonNull(serialization); - return this; - } - - /** - * Sets an {@link AvaticaHandler} directly on the builder. Most users will not want to use - * this method and should instead use {@link #withHandler(Service, Serialization)}. - * - * @param handler The handler - * @return <code>this</code> - */ - public Builder withHandler(AvaticaHandler handler) { - this.handler = Objects.requireNonNull(handler); - return this; - } - - /** - * Sets the given configuration to enable metrics collection in the server. - * - * @param metricsConfig Configuration object for metrics. - * @return <code>this</code> - */ - public Builder withMetricsConfiguration(MetricsSystemConfiguration<?> metricsConfig) { - this.metricsConfig = Objects.requireNonNull(metricsConfig); - return this; - } - - /** - * Configures the server to use SPNEGO authentication. This method requires that the - * <code>principal</code> contains the Kerberos realm. Invoking this method overrides any - * previous call which configures authentication. - * - * @param principal A kerberos principal with the realm required. - * @return <code>this</code> - */ - public Builder withSpnego(String principal) { - return withSpnego(principal, (String[]) null); - } - - /** - * Configures the server to use SPNEGO authentication. This method requires that the - * <code>principal</code> contains the Kerberos realm. Invoking this method overrides any - * previous call which configures authentication. Invoking this method overrides any previous - * call which configures authentication. By default, only principals from the server's realm are - * permitted, but additional realms can be allowed using <code>additionalAllowedRealms</code>. - * - * @param principal A kerberos principal with the realm required. - * @param additionalAllowedRealms Any additional realms, other than the server's realm, which - * should be allowed to authenticate against the server. Can be null. - * @return <code>this</code> - */ - public Builder withSpnego(String principal, String[] additionalAllowedRealms) { - int index = Objects.requireNonNull(principal).lastIndexOf('@'); - if (-1 == index) { - throw new IllegalArgumentException("Could not find '@' symbol in '" + principal - + "' to parse the Kerberos realm from the principal"); - } - final String realm = principal.substring(index + 1); - return withSpnego(principal, realm, additionalAllowedRealms); - } - - /** - * Configures the server to use SPNEGO authentication. It is required that callers are logged - * in via Kerberos already or have provided the necessary configuration to automatically log - * in via JAAS (using the <code>java.security.auth.login.config</code> system property) before - * starting the {@link HttpServer}. Invoking this method overrides any previous call which - * configures authentication. - * - * @param principal The kerberos principal - * @param realm The kerberos realm - * @return <code>this</code> - */ - public Builder withSpnego(String principal, String realm) { - return this.withSpnego(principal, realm, null); - } - - /** - * Configures the server to use SPNEGO authentication. It is required that callers are logged - * in via Kerberos already or have provided the necessary configuration to automatically log - * in via JAAS (using the <code>java.security.auth.login.config</code> system property) before - * starting the {@link HttpServer}. Invoking this method overrides any previous call which - * configures authentication. By default, only principals from the server's realm are permitted, - * but additional realms can be allowed using <code>additionalAllowedRealms</code>. - * - * @param principal The kerberos principal - * @param realm The kerberos realm - * @param additionalAllowedRealms Any additional realms, other than the server's realm, which - * should be allowed to authenticate against the server. Can be null. - * @return <code>this</code> - */ - public Builder withSpnego(String principal, String realm, String[] additionalAllowedRealms) { - this.authenticationType = AuthenticationType.SPNEGO; - this.kerberosPrincipal = Objects.requireNonNull(principal); - this.kerberosRealm = Objects.requireNonNull(realm); - this.loginServiceAllowedRoles = additionalAllowedRealms; - return this; - } - - /** - * Sets a keytab to be used to perform a Kerberos login automatically (without the use of JAAS). - * - * @param keytab A KeyTab file for the server's login. - * @return <code>this</code> - */ - public Builder withAutomaticLogin(File keytab) { - this.keytab = Objects.requireNonNull(keytab); - return this; - } - - /** - * Sets a callback implementation to defer the logic on how to run an action as a given user and - * if the action should be permitted for that user. - * - * @param remoteUserCallback User-provided implementation of the callback - * @return <code>this</code> - */ - public Builder withImpersonation(DoAsRemoteUserCallback remoteUserCallback) { - this.remoteUserCallback = Objects.requireNonNull(remoteUserCallback); - return this; - } - - /** - * Configures the server to use HTTP Basic authentication. The <code>properties</code> must - * be in a form consumable by Jetty. Invoking this method overrides any previous call which - * configures authentication. This authentication is supplementary to the JDBC-provided user - * authentication interfaces and should only be used when those interfaces are not used. - * - * @param properties Location of a properties file parseable by Jetty which contains users and - * passwords. - * @param allowedRoles An array of allowed roles in the properties file - * @return <code>this</code> - */ - public Builder withBasicAuthentication(String properties, String[] allowedRoles) { - return withAuthentication(AuthenticationType.BASIC, properties, allowedRoles); - } - - /** - * Configures the server to use HTTP Digest authentication. The <code>properties</code> must - * be in a form consumable by Jetty. Invoking this method overrides any previous call which - * configures authentication. This authentication is supplementary to the JDBC-provided user - * authentication interfaces and should only be used when those interfaces are not used. - * - * @param properties Location of a properties file parseable by Jetty which contains users and - * passwords. - * @param allowedRoles An array of allowed roles in the properties file - * @return <code>this</code> - */ - public Builder withDigestAuthentication(String properties, String[] allowedRoles) { - return withAuthentication(AuthenticationType.DIGEST, properties, allowedRoles); - } - - private Builder withAuthentication(AuthenticationType authType, String properties, - String[] allowedRoles) { - this.loginServiceRealm = "Avatica"; - this.authenticationType = authType; - this.loginServiceProperties = Objects.requireNonNull(properties); - this.loginServiceAllowedRoles = Objects.requireNonNull(allowedRoles); - return this; - } - - /** - * Configures the server to use TLS for wire encryption. - * - * @param keystore The server's keystore - * @param keystorePassword The keystore's password - * @param truststore The truststore containing the key used to generate the server's key - * @param truststorePassword The truststore's password - * @return <code>this</code> - */ - public Builder withTLS(File keystore, String keystorePassword, File truststore, - String truststorePassword) { - this.usingTLS = true; - this.keystore = Objects.requireNonNull(keystore); - this.keystorePassword = Objects.requireNonNull(keystorePassword); - this.truststore = Objects.requireNonNull(truststore); - this.truststorePassword = Objects.requireNonNull(truststorePassword); - return this; - } - - /** - * Builds the HttpServer instance from <code>this</code>. - * @return An HttpServer. - */ - public HttpServer build() { - final AvaticaServerConfiguration serverConfig; - final Subject subject; - switch (authenticationType) { - case NONE: - serverConfig = null; - subject = null; - break; - case BASIC: - case DIGEST: - // Build the configuration for BASIC or DIGEST authentication. - serverConfig = buildUserAuthenticationConfiguration(this); - subject = null; - break; - case SPNEGO: - if (usingTLS) { - throw new IllegalArgumentException("TLS has not been tested wtih SPNEGO"); - } - if (null != keytab) { - LOG.debug("Performing Kerberos login with {} as {}", keytab, kerberosPrincipal); - subject = loginViaKerberos(this); - } else { - LOG.debug("Not performing Kerberos login"); - subject = null; - } - serverConfig = buildSpnegoConfiguration(this); - break; - default: - throw new IllegalArgumentException("Unhandled AuthenticationType"); - } - - AvaticaHandler handler = buildHandler(this, serverConfig); - SslContextFactory sslFactory = null; - if (usingTLS) { - sslFactory = new SslContextFactory(); - sslFactory.setKeyStorePath(this.keystore.getAbsolutePath()); - sslFactory.setKeyStorePassword(keystorePassword); - sslFactory.setTrustStorePath(truststore.getAbsolutePath()); - sslFactory.setTrustStorePassword(truststorePassword); - } - - return new HttpServer(port, handler, serverConfig, subject, sslFactory); - } - - /** - * Creates the appropriate {@link AvaticaHandler}. - * - * @param b The {@link Builder}. - * @param config The Avatica server configuration - * @return An {@link AvaticaHandler}. - */ - private AvaticaHandler buildHandler(Builder b, AvaticaServerConfiguration config) { - // The user provided a handler explicitly. - if (null != b.handler) { - return b.handler; - } - - // Normal case, we create the handler for the user. - HandlerFactory factory = new HandlerFactory(); - return factory.getHandler(b.service, b.serialization, b.metricsConfig, config); - } - - /** - * Builds an {@link AvaticaServerConfiguration} implementation for SPNEGO-based authentication. - * @param b The {@link Builder}. - * @return A configuration instance. - */ - private AvaticaServerConfiguration buildSpnegoConfiguration(Builder b) { - final String principal = b.kerberosPrincipal; - final String realm = b.kerberosRealm; - final String[] additionalAllowedRealms = b.loginServiceAllowedRoles; - final DoAsRemoteUserCallback callback = b.remoteUserCallback; - return new AvaticaServerConfiguration() { - - @Override public AuthenticationType getAuthenticationType() { - return AuthenticationType.SPNEGO; - } - - @Override public String getKerberosRealm() { - return realm; - } - - @Override public String getKerberosPrincipal() { - return principal; - } - - @Override public boolean supportsImpersonation() { - return null != callback; - } - - @Override public <T> T doAsRemoteUser(String remoteUserName, String remoteAddress, - Callable<T> action) throws Exception { - return callback.doAsRemoteUser(remoteUserName, remoteAddress, action); - } - - @Override public String[] getAllowedRoles() { - return additionalAllowedRealms; - } - - @Override public String getHashLoginServiceRealm() { - return null; - } - - @Override public String getHashLoginServiceProperties() { - return null; - } - }; - } - - private AvaticaServerConfiguration buildUserAuthenticationConfiguration(Builder b) { - final AuthenticationType authType = b.authenticationType; - final String[] allowedRoles = b.loginServiceAllowedRoles; - final String realm = b.loginServiceRealm; - final String properties = b.loginServiceProperties; - - return new AvaticaServerConfiguration() { - @Override public AuthenticationType getAuthenticationType() { - return authType; - } - - @Override public String[] getAllowedRoles() { - return allowedRoles; - } - - @Override public String getHashLoginServiceRealm() { - return realm; - } - - @Override public String getHashLoginServiceProperties() { - return properties; - } - - // Unused - - @Override public String getKerberosRealm() { - return null; - } - - @Override public String getKerberosPrincipal() { - return null; - } - - @Override public boolean supportsImpersonation() { - return false; - } - - @Override public <T> T doAsRemoteUser(String remoteUserName, String remoteAddress, - Callable<T> action) throws Exception { - return null; - } - }; - } - - private Subject loginViaKerberos(Builder b) { - Set<Principal> principals = new HashSet<Principal>(); - principals.add(new KerberosPrincipal(b.kerberosPrincipal)); - - Subject subject = new Subject(false, principals, new HashSet<Object>(), - new HashSet<Object>()); - - KeytabJaasConf conf = new KeytabJaasConf(b.kerberosPrincipal, b.keytab.toString()); - String confName = "NotUsed"; - try { - LoginContext loginContext = new LoginContext(confName, subject, null, conf); - loginContext.login(); - return loginContext.getSubject(); - } catch (LoginException e) { - throw new RuntimeException(e); - } - } - - /** - * Javax Configuration class which always returns a configuration for our keytab-based - * login. - */ - private static class KeytabJaasConf extends javax.security.auth.login.Configuration { - private final String principal; - private final String keytab; - - private KeytabJaasConf(String principal, String keytab) { - this.principal = principal; - this.keytab = keytab; - } - - @Override public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - Map<String, String> options = new HashMap<String, String>(); - options.put("storeKey", "true"); - options.put("principal", principal); - options.put("keyTab", keytab); - options.put("doNotPrompt", "true"); - options.put("useKeyTab", "true"); - options.put("isInitiator", "false"); - options.put("debug", - System.getProperty("sun.security.krb5.debug", "false") - .toLowerCase(Locale.ROOT)); - - return new AppConfigurationEntry[] {new AppConfigurationEntry(getKrb5LoginModuleName(), - AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)}; - } - } - - private static String getKrb5LoginModuleName() { - return System.getProperty("java.vendor").contains("IBM") - ? "com.ibm.security.auth.module.Krb5LoginModule" - : "com.sun.security.auth.module.Krb5LoginModule"; - } - } -} - -// End HttpServer.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/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 deleted file mode 100644 index f2d546b..0000000 --- a/avatica/server/src/main/java/org/apache/calcite/avatica/server/Main.java +++ /dev/null @@ -1,104 +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.server; - -import org.apache.calcite.avatica.Meta; -import org.apache.calcite.avatica.remote.LocalService; -import org.apache.calcite.avatica.remote.Service; - -import org.eclipse.jetty.server.handler.AbstractHandler; - -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; - -/** - * Jetty handler that executes Avatica JSON request-responses. - */ -public class Main { - private Main() {} - - public static void main(String[] args) throws InterruptedException, ClassNotFoundException, - IllegalAccessException, InstantiationException, NoSuchMethodException, - InvocationTargetException { - HttpServer server = start(args); - server.join(); - } - - /** - * Factory that instantiates Jetty Handlers - */ - public interface HandlerFactory { - AbstractHandler createHandler(Service service); - } - - private static final HandlerFactory JSON_HANDLER_FACTORY = new HandlerFactory() { - public AbstractHandler createHandler(Service service) { - return new AvaticaJsonHandler(service); - } - }; - - /** - * Creates and starts an {@link HttpServer} using JSON POJO serialization of requests/responses. - * - * <p>Arguments are as follows: - * <ul> - * <li>args[0]: the {@link org.apache.calcite.avatica.Meta.Factory} class - * name - * <li>args[1+]: arguments passed along to - * {@link org.apache.calcite.avatica.Meta.Factory#create(java.util.List)} - * </ul> - * - * @param args Command-line arguments - */ - public static HttpServer start(String[] args) throws ClassNotFoundException, - InstantiationException, IllegalAccessException, NoSuchMethodException, - InvocationTargetException { - return start(args, 8765, JSON_HANDLER_FACTORY); - } - - /** - * Creates and starts an {@link HttpServer} using the given factory to create the Handler. - * - * <p>Arguments are as follows: - * <ul> - * <li>args[0]: the {@link org.apache.calcite.avatica.Meta.Factory} class - * name - * <li>args[1+]: arguments passed along to - * {@link org.apache.calcite.avatica.Meta.Factory#create(java.util.List)} - * </ul> - * - * @param args Command-line arguments - * @param port Server port to bind - * @param handlerFactory Factory to create the handler used by the server - */ - public static HttpServer start(String[] args, int port, HandlerFactory handlerFactory) - throws ClassNotFoundException, InstantiationException, IllegalAccessException, - NoSuchMethodException, InvocationTargetException { - String factoryClassName = args[0]; - @SuppressWarnings("unchecked") Class<Meta.Factory> factoryClass = - (Class<Meta.Factory>) Class.forName(factoryClassName); - Meta.Factory factory = factoryClass.getConstructor().newInstance(); - Meta meta = factory.create(Arrays.asList(args).subList(1, args.length)); - Service service = new LocalService(meta); - HttpServer server = new HttpServer(port, - HttpServer.wrapJettyHandler(handlerFactory.createHandler(service))); - server.start(); - return server; - } -} - -// End Main.java
