DATAGEODE-192 - Add support for HTTPS and Follow Redirects when using @EnableClusterConfiguration.
This commit is contained in:
@@ -13,25 +13,38 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.admin.remote;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.schema.definitions.IndexDefinition;
|
||||
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.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -44,69 +57,125 @@ import org.springframework.web.client.RestTemplate;
|
||||
* is not supported or has not been implemented against the Management REST API interface over HTTP.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.net.HttpURLConnection
|
||||
* @see java.net.URI
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.execute.Function
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.admin.remote.FunctionGemfireAdminTemplate
|
||||
* @see org.springframework.http.HttpHeaders
|
||||
* @see org.springframework.http.HttpMethod
|
||||
* @see org.springframework.http.HttpStatus
|
||||
* @see org.springframework.http.RequestEntity
|
||||
* @see org.springframework.http.ResponseEntity
|
||||
* @see org.springframework.http.client.ClientHttpRequestFactory
|
||||
* @see org.springframework.http.client.ClientHttpRequestInterceptor
|
||||
* @see org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
* @see org.springframework.web.client.RestTemplate
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
|
||||
protected static final boolean CREATE_REGION_SKIP_IF_EXISTS_DEFAULT = true;
|
||||
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;
|
||||
|
||||
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_URL_TEMPLATE = "http://%1$s:%2$d/gemfire/v1/";
|
||||
protected static final List<String> VALID_SCHEMES = Arrays.asList(HTTP_SCHEME, HTTPS_SCHEME);
|
||||
|
||||
private final RestOperations restTemplate;
|
||||
|
||||
private final String managementRestApiUrl;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link RestHttpGemfireAdminTemplate} initialized with
|
||||
* the given {@link ClientCache} and configured with the default host and port when accessing
|
||||
* the GemFire or Geode Management REST API interface.
|
||||
* Constructs a new instance of {@link RestHttpGemfireAdminTemplate} initialized with the given {@link ClientCache}
|
||||
* and configured with the default host and port when accessing the Apache Geode or Pivotal GemFire
|
||||
* Management REST API interface.
|
||||
*
|
||||
* @param clientCache reference to the {@link ClientCache}
|
||||
* @throws IllegalArgumentException if the {@link ClientCache} reference is {@literal null}.
|
||||
* @param clientCache reference to the {@link ClientCache}.
|
||||
* @throws IllegalArgumentException if {@link ClientCache} is {@literal null}.
|
||||
* @see #RestHttpGemfireAdminTemplate(ClientCache, String, String, int, boolean, List)
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
*/
|
||||
public RestHttpGemfireAdminTemplate(ClientCache clientCache) {
|
||||
this(clientCache, DEFAULT_HOST, DEFAULT_PORT);
|
||||
this(clientCache, DEFAULT_SCHEME, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_HTTP_FOLLOW_REDIRECTS,
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link RestHttpGemfireAdminTemplate} initialized with
|
||||
* the given {@link ClientCache} and configured with the specified host and port when accessing
|
||||
* the GemFire or Geode Management REST API interface.
|
||||
* Constructs a new instance of {@link RestHttpGemfireAdminTemplate} initialized with the given {@link ClientCache}
|
||||
* and configured with the specified HTTP scheme, host, port, redirects and
|
||||
* {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} when
|
||||
* accessing the Apache Geode or Pivotal GemFire Management REST API interface.
|
||||
*
|
||||
* @param clientCache reference to the {@link ClientCache}
|
||||
* @param scheme {@link String} specifying the HTTP scheme to use (e.g. HTTP or HTTPS).
|
||||
* @param host {@link String} containing the hostname of the GemFire/Geode Manager.
|
||||
* @param port integer value specifying the port on which the GemFire/Geode Manager HTTP Service is listening
|
||||
* for HTTP clients.
|
||||
* @param followRedirects boolean indicating whether HTTP Redirects (with HTTP Status Code 3xx) should be followed.
|
||||
* @param clientHttpRequestInterceptors {@link List} of {@link ClientHttpRequestInterceptor} used to intercept
|
||||
* and decorate the HTTP request and HTTP response.
|
||||
* @throws IllegalArgumentException if the {@link ClientCache} reference is {@literal null}.
|
||||
* @see org.springframework.http.client.ClientHttpRequestInterceptor
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see #newClientHttpRequestFactory(boolean)
|
||||
* @see #newRestOperations(ClientHttpRequestFactory, List)
|
||||
* @see #resolveManagementRestApiUrl(String, String, int)
|
||||
*/
|
||||
public RestHttpGemfireAdminTemplate(ClientCache clientCache, String host, int port) {
|
||||
public RestHttpGemfireAdminTemplate(ClientCache clientCache, String scheme, String host, int port,
|
||||
boolean followRedirects, List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors) {
|
||||
|
||||
super(clientCache);
|
||||
|
||||
this.restTemplate = newRestOperations();
|
||||
this.managementRestApiUrl = resolveManagementRestApiUrl(host, port);
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = newClientHttpRequestFactory(followRedirects);
|
||||
|
||||
this.managementRestApiUrl = resolveManagementRestApiUrl(scheme, host, port);
|
||||
this.restTemplate = newRestOperations(clientHttpRequestFactory, clientHttpRequestInterceptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link ClientHttpRequestFactory} to make HTTP client requests.
|
||||
*
|
||||
* @param followRedirects boolean value indicating whether HTTP redirects (with HTTP Status Code 3xx)
|
||||
* should be followed.
|
||||
* @return a new {@link ClientHttpRequestFactory}.
|
||||
* @see org.springframework.http.client.ClientHttpRequestFactory
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T extends ClientHttpRequestFactory> T newClientHttpRequestFactory(boolean followRedirects) {
|
||||
return (T) new FollowRedirectsSimpleClientHttpRequestFactory(followRedirects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the Spring {@link RestTemplate} to perform REST API operations over HTTP.
|
||||
*
|
||||
* @param clientHttpRequestFactory {@link ClientHttpRequestFactory} used to construct HTTP request objects.
|
||||
* @param clientHttpRequestInterceptors {@link List} of {@link ClientHttpRequestInterceptor} used to intercept
|
||||
* and decorate the HTTP request and HTTP response.
|
||||
* @return a new instance of Spring's {@link RestTemplate}.
|
||||
* @see org.springframework.http.client.ClientHttpRequestInterceptor
|
||||
* @see org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
* @see org.springframework.web.client.RestTemplate
|
||||
*/
|
||||
RestOperations newRestOperations() {
|
||||
return new RestTemplate(new SimpleClientHttpRequestFactory());
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T extends RestOperations> T newRestOperations(ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors) {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
|
||||
|
||||
Optional.ofNullable(clientHttpRequestInterceptors)
|
||||
.ifPresent(restTemplate.getInterceptors()::addAll);
|
||||
|
||||
return (T) restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +187,8 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
* @param port integer specifying the port that the embedded Manager's HTTP service is listening on.
|
||||
* @return the resolved URL.
|
||||
*/
|
||||
private String resolveManagementRestApiUrl(String host, int port) {
|
||||
return String.format(MANAGEMENT_REST_API_URL_TEMPLATE, host, port);
|
||||
String resolveManagementRestApiUrl(String scheme, String host, int port) {
|
||||
return String.format(MANAGEMENT_REST_API_URL_TEMPLATE, scheme, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,8 +206,9 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
* @return a reference to the {@link RestOperations} used to perform REST API calls.
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
*/
|
||||
protected RestOperations getRestOperations() {
|
||||
return this.restTemplate;
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T extends RestOperations> T getRestOperations() {
|
||||
return (T) this.restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -149,24 +219,24 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
// HTTP Message Body
|
||||
MultiValueMap<String, Object> requestParameters = new LinkedMultiValueMap<>();
|
||||
MultiValueMap<String, Object> httpRequestParameters = new LinkedMultiValueMap<>();
|
||||
|
||||
requestParameters.add("name", indexDefinition.getName());
|
||||
requestParameters.add("expression", indexDefinition.getExpression());
|
||||
requestParameters.add("region", indexDefinition.getFromClause());
|
||||
requestParameters.add("type", indexDefinition.getIndexType().toString());
|
||||
httpRequestParameters.add("name", indexDefinition.getName());
|
||||
httpRequestParameters.add("expression", indexDefinition.getExpression());
|
||||
httpRequestParameters.add("region", indexDefinition.getFromClause());
|
||||
httpRequestParameters.add("type", indexDefinition.getIndexType().toString());
|
||||
|
||||
RequestEntity<MultiValueMap<String, Object>> requestEntity =
|
||||
new RequestEntity<>(requestParameters, httpHeaders, HttpMethod.POST, resolveCreateIndexUri());
|
||||
new RequestEntity<>(httpRequestParameters, httpHeaders, HttpMethod.POST, resolveCreateIndexUri());
|
||||
|
||||
ResponseEntity<String> response = getRestOperations().exchange(requestEntity, String.class);
|
||||
|
||||
// TODO do something with result; e.g. log when failure (or when not "OK")
|
||||
// TODO do something with the result; e.g. log when failure (or when not "OK")
|
||||
HttpStatus.OK.equals(response.getStatusCode());
|
||||
}
|
||||
|
||||
protected URI resolveCreateIndexUri() {
|
||||
return URI.create(getManagementRestApiUrl().concat("indexes"));
|
||||
return URI.create(getManagementRestApiUrl().concat("/indexes"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,22 +247,113 @@ public class RestHttpGemfireAdminTemplate extends FunctionGemfireAdminTemplate {
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
// HTTP Message Body
|
||||
MultiValueMap<String, Object> requestParameters = new LinkedMultiValueMap<>();
|
||||
MultiValueMap<String, Object> httpRequestParameters = new LinkedMultiValueMap<>();
|
||||
|
||||
requestParameters.add("name", regionDefinition.getName());
|
||||
requestParameters.add("type", regionDefinition.getRegionShortcut().toString());
|
||||
requestParameters.add("skip-if-exists", String.valueOf(CREATE_REGION_SKIP_IF_EXISTS_DEFAULT));
|
||||
httpRequestParameters.add("name", regionDefinition.getName());
|
||||
httpRequestParameters.add("type", regionDefinition.getRegionShortcut().toString());
|
||||
httpRequestParameters.add("skip-if-exists", String.valueOf(DEFAULT_CREATE_REGION_SKIP_IF_EXISTS));
|
||||
|
||||
RequestEntity<MultiValueMap<String, Object>> requestEntity =
|
||||
new RequestEntity<>(requestParameters, httpHeaders, HttpMethod.POST, resolveCreateRegionUri());
|
||||
new RequestEntity<>(httpRequestParameters, httpHeaders, HttpMethod.POST, resolveCreateRegionUri());
|
||||
|
||||
ResponseEntity<String> response = getRestOperations().exchange(requestEntity, String.class);
|
||||
|
||||
// TODO do something with result; e.g. log when failure (or when not "OK")
|
||||
// TODO do something with the result; e.g. log when failure (or when not "OK")
|
||||
HttpStatus.OK.equals(response.getStatusCode());
|
||||
}
|
||||
|
||||
protected URI resolveCreateRegionUri() {
|
||||
return URI.create(getManagementRestApiUrl().concat("regions"));
|
||||
return URI.create(getManagementRestApiUrl().concat("/regions"));
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private boolean followRedirects = DEFAULT_HTTP_FOLLOW_REDIRECTS;
|
||||
|
||||
private int port = DEFAULT_PORT;
|
||||
|
||||
private ClientCache clientCache;
|
||||
|
||||
private final List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors = new ArrayList<>();
|
||||
|
||||
private String hostname = DEFAULT_HOST;
|
||||
private String scheme = DEFAULT_SCHEME;
|
||||
|
||||
public Builder followRedirects(boolean followRedirects) {
|
||||
this.followRedirects = followRedirects;
|
||||
return this;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
this.port = port;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder on(String hostname) {
|
||||
this.hostname = StringUtils.hasText(hostname) ? hostname : DEFAULT_HOST;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder using(String scheme) {
|
||||
|
||||
scheme = String.valueOf(scheme).trim().toLowerCase();
|
||||
|
||||
Assert.isTrue(VALID_SCHEMES.contains(scheme),
|
||||
String.format("Scheme [%s] is not valid; must be 1 of %s", scheme, VALID_SCHEMES));
|
||||
|
||||
this.scheme = scheme;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder with(ClientCache clientCache) {
|
||||
this.clientCache = clientCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder with(ClientHttpRequestInterceptor... clientHttpRequestInterceptors) {
|
||||
|
||||
clientHttpRequestInterceptors =
|
||||
ArrayUtils.nullSafeArray(clientHttpRequestInterceptors, ClientHttpRequestInterceptor.class);
|
||||
|
||||
return with(Arrays.stream(clientHttpRequestInterceptors).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public Builder with(List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors) {
|
||||
this.clientHttpRequestInterceptors.addAll(CollectionUtils.nullSafeList(clientHttpRequestInterceptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
public RestHttpGemfireAdminTemplate build() {
|
||||
|
||||
return new RestHttpGemfireAdminTemplate(this.clientCache, this.scheme, this.hostname, this.port,
|
||||
this.followRedirects, this.clientHttpRequestInterceptors);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FollowRedirectsSimpleClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
|
||||
|
||||
private final boolean followRedirects;
|
||||
|
||||
public FollowRedirectsSimpleClientHttpRequestFactory(boolean followRedirects) {
|
||||
this.followRedirects = followRedirects;
|
||||
}
|
||||
|
||||
public boolean isFollowRedirects() {
|
||||
return this.followRedirects;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
|
||||
|
||||
super.prepareConnection(connection, httpMethod);
|
||||
|
||||
connection.setInstanceFollowRedirects(isFollowRedirects());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,26 +13,34 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.springframework.data.gemfire.util.CacheUtils.isClient;
|
||||
import static org.springframework.data.gemfire.util.CacheUtils.isPeer;
|
||||
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.config.admin.GemfireAdminOperations;
|
||||
import org.springframework.data.gemfire.config.admin.remote.FunctionGemfireAdminTemplate;
|
||||
@@ -49,7 +57,9 @@ 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.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration @Configuration} class defining Spring beans that will record the creation of
|
||||
@@ -57,32 +67,54 @@ import org.springframework.util.Assert;
|
||||
* as Spring beans in the Spring container.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.annotation.Annotation
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.apache.geode.cache.query.Index
|
||||
* @see org.springframework.beans.factory.ListableBeanFactory
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.ImportAware
|
||||
* @see org.springframework.context.event.EventListener
|
||||
* @see org.springframework.core.annotation.AnnotationAttributes
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.core.type.AnnotationMetadata
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
|
||||
* @see org.springframework.http.client.ClientHttpRequestInterceptor
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
|
||||
|
||||
protected static final boolean DEFAULT_HTTP_FOLLOW_REDIRECTS = false;
|
||||
protected static final boolean DEFAULT_MANAGEMENT_USE_HTTP = false;
|
||||
protected static final boolean DEFAULT_MANAGEMENT_REQUIRE_HTTPS = true;
|
||||
|
||||
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_SCHEME = "http";
|
||||
protected static final String HTTPS_SCHEME = "https";
|
||||
|
||||
private static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionDefinition.DEFAULT_REGION_SHORTCUT;
|
||||
|
||||
private Boolean requireHttps = DEFAULT_MANAGEMENT_REQUIRE_HTTPS;
|
||||
private Boolean useHttp = DEFAULT_MANAGEMENT_USE_HTTP;
|
||||
|
||||
private Integer managementHttpPort = DEFAULT_MANAGEMENT_HTTP_PORT;
|
||||
|
||||
@Autowired(required = false)
|
||||
private GemfireAdminOperations gemfireAdminOperations;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<ClientHttpRequestInterceptor> clientHttpRequestInterceptors;
|
||||
|
||||
private RegionShortcut serverRegionShortcut;
|
||||
|
||||
private String managementHttpHost = DEFAULT_MANAGEMENT_HTTP_HOST;
|
||||
@@ -97,7 +129,7 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
}
|
||||
|
||||
protected Optional<String> getManagementHttpHost() {
|
||||
return Optional.ofNullable(this.managementHttpHost);
|
||||
return Optional.ofNullable(this.managementHttpHost).filter(StringUtils::hasText);
|
||||
}
|
||||
|
||||
protected String resolveManagementHttpHost() {
|
||||
@@ -116,6 +148,18 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
return getManagementHttpPort().orElse(DEFAULT_MANAGEMENT_HTTP_PORT);
|
||||
}
|
||||
|
||||
protected void setManagementRequireHttps(Boolean requireHttps) {
|
||||
this.requireHttps = requireHttps;
|
||||
}
|
||||
|
||||
protected Optional<Boolean> getManagementRequireHttps() {
|
||||
return Optional.ofNullable(this.requireHttps);
|
||||
}
|
||||
|
||||
protected boolean resolveManagementRequireHttps() {
|
||||
return getManagementRequireHttps().orElse(DEFAULT_MANAGEMENT_REQUIRE_HTTPS);
|
||||
}
|
||||
|
||||
protected void setManagementUseHttp(Boolean useHttp) {
|
||||
this.useHttp = useHttp;
|
||||
}
|
||||
@@ -153,6 +197,9 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
setManagementHttpPort(resolveProperty(managementProperty("http.port"),
|
||||
enableClusterConfigurationAttributes.<Integer>getNumber("port")));
|
||||
|
||||
setManagementRequireHttps(resolveProperty(managementProperty("require-https"),
|
||||
enableClusterConfigurationAttributes.getBoolean("requireHttps")));
|
||||
|
||||
setManagementUseHttp(resolveProperty(managementProperty("use-http"),
|
||||
enableClusterConfigurationAttributes.getBoolean("useHttp")));
|
||||
|
||||
@@ -162,14 +209,15 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClusterSchemaObjectInitializer gemfireClusterSchemaObjectInitializer(GemFireCache gemfireCache) {
|
||||
public ClusterSchemaObjectInitializer gemfireClusterSchemaObjectInitializer(Environment environment,
|
||||
GemFireCache gemfireCache) {
|
||||
|
||||
return Optional.ofNullable(gemfireCache)
|
||||
.filter(CacheUtils::isClient)
|
||||
.map(clientCache -> {
|
||||
|
||||
SchemaObjectContext schemaObjectContext = SchemaObjectContext.from(gemfireCache)
|
||||
.with(newGemfireAdminOperations((ClientCache) clientCache))
|
||||
.with(resolveGemfireAdminOperations(environment, (ClientCache) clientCache))
|
||||
.with(newSchemaObjectCollector())
|
||||
.with(newSchemaObjectDefiner());
|
||||
|
||||
@@ -180,24 +228,92 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link GemfireAdminOperations} to perform administrative, schema functions
|
||||
* Attempts to resolve a {@link List} of {@link ClientHttpRequestInterceptor} beans in the Spring
|
||||
* {@link ApplicationContext}.
|
||||
*
|
||||
* @return a {@link List} of declared and registered {@link ClientHttpRequestInterceptor} beans.
|
||||
* @see org.springframework.http.client.ClientHttpRequestInterceptor
|
||||
* @see #getBeanFactory()
|
||||
* @see java.util.List
|
||||
*/
|
||||
protected List<ClientHttpRequestInterceptor> resolveClientHttpRequestInterceptors() {
|
||||
|
||||
return Optional.ofNullable(this.clientHttpRequestInterceptors)
|
||||
.orElseGet(() ->
|
||||
|
||||
Optional.of(getBeanFactory())
|
||||
.filter(ListableBeanFactory.class::isInstance)
|
||||
.map(ListableBeanFactory.class::cast)
|
||||
.map(beanFactory -> {
|
||||
|
||||
Map<String, ClientHttpRequestInterceptor> beansOfType = beanFactory
|
||||
.getBeansOfType(ClientHttpRequestInterceptor.class, true, false);
|
||||
|
||||
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
|
||||
|
||||
})
|
||||
.orElseGet(Collections::emptyList));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the the {@link GemfireAdminOperations} object from the Spring {@link ApplicationContext}
|
||||
* which is used to create Apache Geode or Pivotal GemFire schema objects.
|
||||
*
|
||||
* @param environment reference to the {@link Environment}.
|
||||
* @param clientCache reference to the {@link ClientCache}.
|
||||
* @return the resovled {@link GemfireAdminOperations} instance.
|
||||
* @see org.springframework.core.env.Environment
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see #newGemfireAdminOperations(Environment, ClientCache)
|
||||
*/
|
||||
protected GemfireAdminOperations resolveGemfireAdminOperations(Environment environment, ClientCache clientCache) {
|
||||
|
||||
return Optional.ofNullable(this.gemfireAdminOperations)
|
||||
.orElseGet(() -> newGemfireAdminOperations(environment, clientCache));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link GemfireAdminOperations} to perform administrative, schema functions
|
||||
* on a GemFire cache cluster as well as a client cache from a cache client.
|
||||
*
|
||||
* @param environment reference to the {@link Environment}.
|
||||
* @param clientCache {@link ClientCache} instance used by the {@link GemfireAdminOperations} interface
|
||||
* to access the GemFire system.
|
||||
* @return an implementation of the {@link GemfireAdminOperations} interface to perform administrative functions
|
||||
* on a GemFire system.
|
||||
* @see org.springframework.data.gemfire.config.admin.GemfireAdminOperations
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see #resolveClientHttpRequestInterceptors()
|
||||
* @see #resolveManagementHttpHost()
|
||||
* @see #resolveManagementHttpPort()
|
||||
* @see #resolveManagementRequireHttps()
|
||||
* @see #resolveManagementUseHttp()
|
||||
*/
|
||||
private GemfireAdminOperations newGemfireAdminOperations(ClientCache clientCache) {
|
||||
private GemfireAdminOperations newGemfireAdminOperations(Environment environment, ClientCache clientCache) {
|
||||
|
||||
if (resolveManagementUseHttp()) {
|
||||
|
||||
String host = resolveManagementHttpHost();
|
||||
boolean setFollowRedirects =
|
||||
environment.getProperty(HTTP_FOLLOW_REDIRECTS_PROPERTY, Boolean.class, DEFAULT_HTTP_FOLLOW_REDIRECTS);
|
||||
|
||||
boolean requireHttps = resolveManagementRequireHttps();
|
||||
boolean followRedirects = !requireHttps || setFollowRedirects;
|
||||
|
||||
int port = resolveManagementHttpPort();
|
||||
|
||||
return new RestHttpGemfireAdminTemplate(clientCache, host, port);
|
||||
String host = resolveManagementHttpHost();
|
||||
String scheme = requireHttps ? HTTPS_SCHEME : HTTP_SCHEME;
|
||||
|
||||
return new RestHttpGemfireAdminTemplate.Builder()
|
||||
.with(resolveClientHttpRequestInterceptors())
|
||||
.with(clientCache)
|
||||
.using(scheme)
|
||||
.on(host)
|
||||
.listenOn(port)
|
||||
.followRedirects(followRedirects)
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
return new FunctionGemfireAdminTemplate(clientCache);
|
||||
@@ -205,7 +321,7 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link SchemaObjectCollector} to inspect the application's context
|
||||
* 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.
|
||||
*
|
||||
* @return a new instance of {@link SchemaObjectCollector} to inspect a GemFire system schema
|
||||
@@ -221,7 +337,7 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link SchemaObjectDefiner} used to reverse engineer a GemFire schema object instance
|
||||
* Constructs a new instance of {@link SchemaObjectDefiner} used to reverse engineer a GemFire schema object instance
|
||||
* to build a definition.
|
||||
*
|
||||
* @return a new instance of {@link SchemaObjectDefiner}.
|
||||
@@ -240,7 +356,9 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
private final SchemaObjectContext schemaObjectContext;
|
||||
|
||||
protected ClusterSchemaObjectInitializer(SchemaObjectContext schemaObjectContext) {
|
||||
|
||||
Assert.notNull(schemaObjectContext, "SchemaObjectContext is required");
|
||||
|
||||
this.schemaObjectContext = schemaObjectContext;
|
||||
}
|
||||
|
||||
@@ -254,7 +372,7 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
protected SchemaObjectContext getSchemaObjectContext() {
|
||||
public SchemaObjectContext getSchemaObjectContext() {
|
||||
return this.schemaObjectContext;
|
||||
}
|
||||
|
||||
@@ -268,14 +386,16 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
Iterable<?> schemaObjects = schemaObjectContext.getSchemaObjectCollector()
|
||||
.collectFrom(requireApplicationContext());
|
||||
|
||||
stream(schemaObjects.spliterator(), false)
|
||||
//Iterable<?> cacheSchemaObjects = schemaObjectContext.getSchemaObjectCollector()
|
||||
// .collectFrom(schemaObjectContext.<GemFireCache>getGemfireCache());
|
||||
|
||||
StreamSupport.stream(schemaObjects.spliterator(), false)
|
||||
.map(schemaObjectContext.getSchemaObjectDefiner()::define)
|
||||
.sorted(OrderComparator.INSTANCE)
|
||||
.forEach(schemaObjectDefinition -> schemaObjectDefinition
|
||||
.ifPresent(it -> it.create(schemaObjectContext.getGemfireAdminOperations())));
|
||||
.forEach(schemaObjectDefinition -> schemaObjectDefinition.ifPresent(it ->
|
||||
it.create(schemaObjectContext.getGemfireAdminOperations())));
|
||||
|
||||
setRunning(true);
|
||||
|
||||
}
|
||||
/*
|
||||
else if (schemaObjectContext.isPeerCache()) {
|
||||
@@ -285,7 +405,6 @@ public class ClusterConfigurationConfiguration extends AbstractAnnotationConfigS
|
||||
|
||||
GemfireFunctionUtils.registerFunctionForPojoMethod(new CreateIndexFunction(),
|
||||
CreateIndexFunction.CREATE_INDEX_FUNCTION_ID);
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
@@ -26,19 +25,22 @@ import java.lang.annotation.Target;
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionShortcut;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The {@link EnableClusterConfiguration} annotation enables Apache Geode / Pivotal GemFire schema-like definitions
|
||||
* defined in a Spring [Boot], Geode/GemFire cache client application using Spring config to be pushed to
|
||||
* a Geode/GemFire cluster, similar to how schema commands (e.g. `create region`) in Gfsh are processed by
|
||||
* an Geode/GemFire Manager.
|
||||
* The {@link EnableClusterConfiguration} annotation enables Apache Geode / Pivotal GemFire schema object definitions
|
||||
* defined in a Spring [Boot], Apache Geode / Pivotal GemFire {@link ClientCache} application using Spring config
|
||||
* to be pushed to an Apache Geode / Pivotal GemFire cluster, similar to how schema commands (e.g. `create region`)
|
||||
* in Gfsh are processed by an Apache Geode / Pivotal GemFire Manager.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.annotation.Documented
|
||||
* @see java.lang.annotation.Inherited
|
||||
* @see java.lang.annotation.Retention
|
||||
* @see java.lang.annotation.Target
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.config.annotation.ClusterConfigurationConfiguration
|
||||
* @since 2.0.0
|
||||
@@ -75,6 +77,18 @@ public @interface EnableClusterConfiguration {
|
||||
*/
|
||||
int port() default ClusterConfigurationConfiguration.DEFAULT_MANAGEMENT_HTTP_PORT;
|
||||
|
||||
/**
|
||||
* Configures whether the HTTP connection between Spring and Apache Geode or Pivotal GemFire should be secure.
|
||||
* That is, whether the HTTP connections uses TLS and results in a secure HTTPS connection rather a plain text
|
||||
* HTTP connection.
|
||||
*
|
||||
* Alternatively, you can configure this setting using the {@literal spring.data.gemfire.management.require-https}
|
||||
* property in {@literal application.properties}.
|
||||
*
|
||||
* Defaults to {@literal true}.
|
||||
*/
|
||||
boolean requireHttps() default ClusterConfigurationConfiguration.DEFAULT_MANAGEMENT_REQUIRE_HTTPS;
|
||||
|
||||
/**
|
||||
* Configuration setting used to specify the data management policy used when creating {@link Region Regions}
|
||||
* on the servers in the Geode/GemFire cluster.
|
||||
|
||||
Reference in New Issue
Block a user