DATAGEODE-196 - Add support for dynamic HTTP client port configuration based on protocol/scheme.

This commit is contained in:
John Blum
2019-05-20 15:12:32 -07:00
parent ac8da3b238
commit 1b4eec323a
9 changed files with 245 additions and 38 deletions

View File

@@ -23,7 +23,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.execute.Function;
@@ -32,6 +31,7 @@ import org.springframework.data.gemfire.config.schema.definitions.IndexDefinitio
import org.springframework.data.gemfire.config.schema.definitions.RegionDefinition;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.util.NetworkUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
@@ -80,13 +80,16 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
protected static final boolean DEFAULT_CREATE_REGION_SKIP_IF_EXISTS = true;
protected static final boolean DEFAULT_HTTP_FOLLOW_REDIRECTS = true;
protected static final int DEFAULT_PORT = 7070;
// Default port to -1 to let HTTP clients determine the port from the protocol/scheme.
// By default, Apache Geode / Pivotal GemFire's (embedded) HTTP service listens on port 7070.
protected static final int DEFAULT_PORT = -1;
protected static final String DEFAULT_HOST = "localhost";
protected static final String DEFAULT_SCHEME = "https";
protected static final String HTTP_SCHEME = "http";
protected static final String HTTPS_SCHEME = "https";
protected static final String MANAGEMENT_REST_API_URL_TEMPLATE = "%1$s://%2$s:%3$d/gemfire/v1";
protected static final String MANAGEMENT_REST_API_NO_PORT_URL_TEMPLATE = "%1$s://%2$s/gemfire/v1";
protected static final List<String> VALID_SCHEMES = Arrays.asList(HTTP_SCHEME, HTTPS_SCHEME);
@@ -105,6 +108,7 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
* @see org.apache.geode.cache.client.ClientCache
*/
public RestHttpGemfireAdminTemplate(ClientCache clientCache) {
this(clientCache, DEFAULT_SCHEME, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_HTTP_FOLLOW_REDIRECTS,
Collections.emptyList());
}
@@ -188,7 +192,10 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
* @return the resolved URL.
*/
String resolveManagementRestApiUrl(String scheme, String host, int port) {
return String.format(MANAGEMENT_REST_API_URL_TEMPLATE, scheme, host, port);
return NetworkUtils.isValidNonEphemeralPort(port)
? String.format(MANAGEMENT_REST_API_URL_TEMPLATE, scheme, host, port)
: String.format(MANAGEMENT_REST_API_NO_PORT_URL_TEMPLATE, scheme, host);
}
/**
@@ -286,8 +293,8 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
public Builder listenOn(int port) {
Assert.isTrue(port > 0 && port < 65536,
String.format("Port [%d] must be greater than 0 and less than 65536", port));
Assert.isTrue(NetworkUtils.isValidNonEphemeralPort(port),
String.format(NetworkUtils.INVALID_NO_EPHEMERAL_PORT_MESSAGE, port));
this.port = port;
@@ -321,11 +328,13 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
clientHttpRequestInterceptors =
ArrayUtils.nullSafeArray(clientHttpRequestInterceptors, ClientHttpRequestInterceptor.class);
return with(Arrays.stream(clientHttpRequestInterceptors).collect(Collectors.toList()));
return with(Arrays.asList(clientHttpRequestInterceptors));
}
public Builder with(List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors) {
this.clientHttpRequestInterceptors.addAll(CollectionUtils.nullSafeList(clientHttpRequestInterceptors));
return this;
}

View File

@@ -57,6 +57,7 @@ import org.springframework.data.gemfire.config.schema.support.IndexDefiner;
import org.springframework.data.gemfire.config.schema.support.RegionDefiner;
import org.springframework.data.gemfire.config.support.AbstractSmartLifecycle;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.data.gemfire.util.NetworkUtils;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -97,8 +98,7 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
protected static final int DEFAULT_MANAGEMENT_HTTP_PORT = HttpServiceConfiguration.DEFAULT_HTTP_SERVICE_PORT;
protected static final String DEFAULT_MANAGEMENT_HTTP_HOST = "localhost";
protected static final String HTTP_FOLLOW_REDIRECTS_PROPERTY =
"spring.data.gemfire.management.http.follow-redirects";
protected static final String HTTP_FOLLOW_REDIRECTS_PROPERTY = "spring.data.gemfire.management.http.follow-redirects";
protected static final String HTTP_SCHEME = "http";
protected static final String HTTPS_SCHEME = "https";
@@ -306,13 +306,12 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
String host = resolveManagementHttpHost();
String scheme = requireHttps ? HTTPS_SCHEME : HTTP_SCHEME;
return new RestHttpGemfireAdminTemplate.Builder()
return configurePort(new RestHttpGemfireAdminTemplate.Builder()
.with(resolveClientHttpRequestInterceptors())
.with(clientCache)
.using(scheme)
.on(host)
.listenOn(port)
.followRedirects(followRedirects)
.followRedirects(followRedirects), port)
.build();
}
else {
@@ -320,6 +319,13 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
}
}
private RestHttpGemfireAdminTemplate.Builder configurePort(RestHttpGemfireAdminTemplate.Builder builder, int port) {
return NetworkUtils.isValidNonEphemeralPort(port)
? builder.listenOn(port)
: builder;
}
/**
* Constructs a new instance of {@link SchemaObjectCollector} to inspect the application's context
* and find all the GemFire schema objects declared of a particular type or types.

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.util;
/**
* Abstract utility class providing functions for networking.
*
* @author John Blum
* @since 2.2.0
*/
public abstract class NetworkUtils {
public static final String INVALID_PORT_MESSAGE =
"Port [%d] must be greater than equal to 0 and less than 65536";
public static final String INVALID_NO_EPHEMERAL_PORT_MESSAGE =
"Port [%d] must be greater than 0 and less than 65536";
/**
* Determines whether the given {@link Integer#TYPE port} is valid.
*
* Technically, port 0 is valid too but no client would use port 0 (the ephemeral port) to connect to a service.
*
* @param port port to evaluate.
* @return a boolean value indicating whether the {@link Integer#TYPE port} is valid or not.
*/
public static boolean isValidPort(int port) {
return port > -1 && port < 65536;
}
public static boolean isValidNonEphemeralPort(int port) {
return isValidPort(port) && port > 0;
}
}