From b7fd39a2625719971713771d4cfb798b92cd945d Mon Sep 17 00:00:00 2001 From: ashasomayajula Date: Sat, 5 Dec 2020 11:05:32 -0600 Subject: [PATCH 1/4] Provide out-of-the-box support for Elasticsearch Sniffer #24174 Added autoconfig support and tests for the elastic search sniffer. --- .../spring-boot-autoconfigure/build.gradle | 1 + ...ElasticsearchSnifferAutoConfiguration.java | 78 ++++++++++++++ .../sniff/ElasticsearchSnifferProperties.java | 58 ++++++++++ .../sniff/SnifferBuilderCustomizer.java | 42 ++++++++ ...icsearchSnifferAutoConfigurationTests.java | 100 ++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index b20e4d383e51..e520c25bf4b8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -77,6 +77,7 @@ dependencies { optional("org.ehcache:ehcache") optional("org.elasticsearch.client:elasticsearch-rest-client") optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") + optional("org.elasticsearch.client:elasticsearch-rest-client-sniffer") optional("org.flywaydb:flyway-core") optional("org.freemarker:freemarker") optional("org.glassfish.jersey.core:jersey-server") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java new file mode 100644 index 000000000000..183d6a1d2928 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.boot.autoconfigure.elasticsearch.sniff; + +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.sniff.Sniffer; +import org.elasticsearch.client.sniff.SnifferBuilder; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.context.properties.PropertyMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Sniffer. + * + * @since + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(RestHighLevelClient.class) +@ConditionalOnMissingBean(RestClient.class) +@EnableConfigurationProperties(ElasticsearchSnifferProperties.class) +public class ElasticsearchSnifferAutoConfiguration { + + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean(SnifferBuilder.class) + static class SnifferBuilderConfiguration { + + @Bean + SnifferBuilderCustomizer defaultSnifferBuilderCustomizer(ElasticsearchSnifferProperties properties) { + return new DefaultSnifferBuilderCustomizer(properties); + } + + @Bean + Sniffer elasticsearchSnifferBuilder(ElasticsearchSnifferProperties properties, + RestClient elasticsearchRestClient) { + return Sniffer.builder(elasticsearchRestClient).build(); + } + } + + static class DefaultSnifferBuilderCustomizer implements SnifferBuilderCustomizer { + + private static final PropertyMapper map = PropertyMapper.get(); + + private final ElasticsearchSnifferProperties properties; + + DefaultSnifferBuilderCustomizer(ElasticsearchSnifferProperties properties) { + this.properties = properties; + } + + @Override + public void customize(SnifferBuilder builder) { + map.from(this.properties::getSniffIntervalMillis).whenNonNull().asInt(Duration::toMillis) + .to(builder::setSniffIntervalMillis); + map.from(this.properties::getSniffFailureDelayMillis).whenNonNull().asInt(Duration::toMillis) + .to(builder::setSniffAfterFailureDelayMillis); + } + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java new file mode 100644 index 000000000000..ea065030717f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.boot.autoconfigure.elasticsearch.sniff; + +import org.elasticsearch.client.sniff.NodesSniffer; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Configuration properties for Elasticsearch sniffer. + * + */ +@ConfigurationProperties(prefix = "spring.elasticsearch.sniff") +public class ElasticsearchSnifferProperties { + + /** + * Sniffer interval millis + */ + private Duration sniffIntervalMillis = Duration.ofMillis(1L); + /** + * Sniffer failure delay millis. + */ + private Duration sniffFailureDelayMillis = Duration.ofMillis(1L); + + public Duration getSniffIntervalMillis() { + return sniffIntervalMillis; + } + + public void setSniffIntervalMillis(Duration sniffIntervalMillis) { + this.sniffIntervalMillis = sniffIntervalMillis; + } + + public Duration getSniffFailureDelayMillis() { + return sniffFailureDelayMillis; + } + + public void setSniffFailureDelayMillis(Duration sniffFailureDelayMillis) { + this.sniffFailureDelayMillis = sniffFailureDelayMillis; + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java new file mode 100644 index 000000000000..cd9728421a5a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.boot.autoconfigure.elasticsearch.sniff; + +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.sniff.SnifferBuilder; + +/** + * Callback interface that can be implemented by beans wishing to further customize the + * {@link org.elasticsearch.client.sniff.Sniffer} via a {@link org.elasticsearch.client.sniff.SnifferBuilder} whilst + * retaining default auto-configuration. + * + */ +@FunctionalInterface +public interface SnifferBuilderCustomizer { + + /** + * Customize the {@link org.elasticsearch.client.sniff.SnifferBuilder}. + *

+ * Possibly overrides customizations made with the {@code "spring.elasticsearch.client.sniff"} + * configuration properties namespace. For more targeted changes, see + + * @param builder the builder to customize + */ + void customize(SnifferBuilder builder); +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java new file mode 100644 index 000000000000..88e554af8da7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.boot.autoconfigure.elasticsearch.sniff; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.client.*; +import org.elasticsearch.client.sniff.ElasticsearchNodesSniffer; +import org.elasticsearch.client.sniff.NodesSniffer; +import org.elasticsearch.client.sniff.Sniffer; +import org.elasticsearch.client.sniff.SnifferBuilder; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.autoconfigure.elasticsearch.sniff.SnifferBuilderCustomizer; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.testsupport.testcontainers.DockerImageNames; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link org.springframework.boot.autoconfigure.elasticsearch.sniff.ElasticsearchSnifferAutoConfiguration}. + * + * @author Asha Somayajula + */ +@Testcontainers(disabledWithoutDocker = true) +class ElasticsearchSnifferAutoConfigurationTests { + + @Container + static final ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch()) + .withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10)); + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class)); + + @Test + void configureShouldOnlyCreateSnifferInstance() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class)); + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Sniffer.class)); + } + + @Configuration(proxyBeanMethods = false) + static class BuilderCustomizerConfiguration { + + @Bean + SnifferBuilderCustomizer myCustomizer() { + return new SnifferBuilderCustomizer() { + + @Override + public void customize(SnifferBuilder builder) { + builder.setSniffAfterFailureDelayMillis(100); + builder.setSniffIntervalMillis(100); + NodesSniffer nodesSniffer = new NodesSniffer() { + @Override + public List sniff() throws IOException { + return null; + } + }; + + builder.setNodesSniffer(nodesSniffer); + } + }; + }; + } + } From 5abf54235d071ebaa8fb875d994825062fe8825f Mon Sep 17 00:00:00 2001 From: ashasomayajula Date: Mon, 21 Dec 2020 11:07:45 -0600 Subject: [PATCH 2/4] Fixes per review. --- .../spring-boot-autoconfigure/build.gradle | 2 +- ...sticsearchRestClientAutoConfiguration.java | 14 +++ .../ElasticsearchSnifferProperties.java | 27 +++-- ...ElasticsearchSnifferAutoConfiguration.java | 78 -------------- .../sniff/SnifferBuilderCustomizer.java | 42 -------- ...earchRestClientAutoConfigurationTests.java | 37 +++++++ ...icsearchSnifferAutoConfigurationTests.java | 100 ------------------ 7 files changed, 65 insertions(+), 235 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/{sniff => }/ElasticsearchSnifferProperties.java (58%) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index e520c25bf4b8..3fe8e6d23b0e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -76,8 +76,8 @@ dependencies { optional("org.eclipse.jetty.websocket:javax-websocket-server-impl") optional("org.ehcache:ehcache") optional("org.elasticsearch.client:elasticsearch-rest-client") - optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") optional("org.elasticsearch.client:elasticsearch-rest-client-sniffer") + optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") optional("org.flywaydb:flyway-core") optional("org.freemarker:freemarker") optional("org.glassfish.jersey.core:jersey-server") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java index e30da5b261b0..b4979bb71d7c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java @@ -19,6 +19,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; +import java.time.temporal.TemporalUnit; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -31,6 +32,8 @@ import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.sniff.Sniffer; +import org.elasticsearch.client.sniff.SnifferBuilder; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -80,6 +83,17 @@ RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperti return builder; } + @Bean + Sniffer elasticsearchSnifferBuilder(ElasticsearchSnifferProperties properties, + RestClient elasticSearchRestClient) { + return Sniffer.builder(elasticSearchRestClient) + .setSniffIntervalMillis( + Math.toIntExact(properties.getSniffInterval().getSeconds() * 1000)) + .setSniffAfterFailureDelayMillis( + Math.toIntExact(properties.getSniffFailureDelay().getSeconds() * 1000)) + .build(); + } + private HttpHost createHttpHost(String uri) { try { return createHttpHost(URI.create(uri)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java similarity index 58% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java index ea065030717f..a547f2b56ce7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.elasticsearch.sniff; +package org.springframework.boot.autoconfigure.elasticsearch; import org.elasticsearch.client.sniff.NodesSniffer; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -25,34 +25,33 @@ import java.util.List; /** - * Configuration properties for Elasticsearch sniffer. * */ @ConfigurationProperties(prefix = "spring.elasticsearch.sniff") public class ElasticsearchSnifferProperties { /** - * Sniffer interval millis + * Sniffer interval */ - private Duration sniffIntervalMillis = Duration.ofMillis(1L); + private Duration sniffInterval = Duration.ofMinutes(5L); /** - * Sniffer failure delay millis. + * Sniffer failure delay. */ - private Duration sniffFailureDelayMillis = Duration.ofMillis(1L); + private Duration sniffFailureDelay = Duration.ofMinutes(1L); - public Duration getSniffIntervalMillis() { - return sniffIntervalMillis; + public Duration getSniffInterval() { + return sniffInterval; } - public void setSniffIntervalMillis(Duration sniffIntervalMillis) { - this.sniffIntervalMillis = sniffIntervalMillis; + public void setSniffInterval(Duration sniffInterval) { + this.sniffInterval = sniffInterval; } - public Duration getSniffFailureDelayMillis() { - return sniffFailureDelayMillis; + public Duration getSniffFailureDelay() { + return sniffFailureDelay; } - public void setSniffFailureDelayMillis(Duration sniffFailureDelayMillis) { - this.sniffFailureDelayMillis = sniffFailureDelayMillis; + public void setSniffFailureDelay(Duration sniffFailureDelay) { + this.sniffFailureDelay = sniffFailureDelay; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java deleted file mode 100644 index 183d6a1d2928..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfiguration.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.boot.autoconfigure.elasticsearch.sniff; - -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestHighLevelClient; -import org.elasticsearch.client.sniff.Sniffer; -import org.elasticsearch.client.sniff.SnifferBuilder; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.context.properties.PropertyMapper; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.time.Duration; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Sniffer. - * - * @since - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(RestHighLevelClient.class) -@ConditionalOnMissingBean(RestClient.class) -@EnableConfigurationProperties(ElasticsearchSnifferProperties.class) -public class ElasticsearchSnifferAutoConfiguration { - - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(SnifferBuilder.class) - static class SnifferBuilderConfiguration { - - @Bean - SnifferBuilderCustomizer defaultSnifferBuilderCustomizer(ElasticsearchSnifferProperties properties) { - return new DefaultSnifferBuilderCustomizer(properties); - } - - @Bean - Sniffer elasticsearchSnifferBuilder(ElasticsearchSnifferProperties properties, - RestClient elasticsearchRestClient) { - return Sniffer.builder(elasticsearchRestClient).build(); - } - } - - static class DefaultSnifferBuilderCustomizer implements SnifferBuilderCustomizer { - - private static final PropertyMapper map = PropertyMapper.get(); - - private final ElasticsearchSnifferProperties properties; - - DefaultSnifferBuilderCustomizer(ElasticsearchSnifferProperties properties) { - this.properties = properties; - } - - @Override - public void customize(SnifferBuilder builder) { - map.from(this.properties::getSniffIntervalMillis).whenNonNull().asInt(Duration::toMillis) - .to(builder::setSniffIntervalMillis); - map.from(this.properties::getSniffFailureDelayMillis).whenNonNull().asInt(Duration::toMillis) - .to(builder::setSniffAfterFailureDelayMillis); - } - } -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java deleted file mode 100644 index cd9728421a5a..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/SnifferBuilderCustomizer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.boot.autoconfigure.elasticsearch.sniff; - -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.sniff.SnifferBuilder; - -/** - * Callback interface that can be implemented by beans wishing to further customize the - * {@link org.elasticsearch.client.sniff.Sniffer} via a {@link org.elasticsearch.client.sniff.SnifferBuilder} whilst - * retaining default auto-configuration. - * - */ -@FunctionalInterface -public interface SnifferBuilderCustomizer { - - /** - * Customize the {@link org.elasticsearch.client.sniff.SnifferBuilder}. - *

- * Possibly overrides customizations made with the {@code "spring.elasticsearch.client.sniff"} - * configuration properties namespace. For more targeted changes, see - - * @param builder the builder to customize - */ - void customize(SnifferBuilder builder); -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java index 364cd1620ed3..1dab5e8874db 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java @@ -16,8 +16,10 @@ package org.springframework.boot.autoconfigure.elasticsearch; +import java.io.IOException; import java.time.Duration; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.http.HttpHost; @@ -34,6 +36,10 @@ import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.sniff.NodesSniffer; +import org.elasticsearch.client.sniff.Sniffer; +import org.elasticsearch.client.sniff.SnifferBuilder; +import org.junit.Assert; import org.junit.jupiter.api.Test; import org.testcontainers.elasticsearch.ElasticsearchContainer; import org.testcontainers.junit.jupiter.Container; @@ -220,6 +226,37 @@ void configureUriWithUsernameAndPasswordWhenUsernameAndPasswordPropertiesSet() { }); } + @Test + void configureShouldOnlyCreateSnifferInstance() { + this.contextRunner.run( + (context) -> assertThat(context).doesNotHaveBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class)); + this.contextRunner.run( + (context) -> assertThat(context).hasSingleBean(Sniffer.class)); + } + + @Test + void configureShouldHaveSnifferInstance() { + this.contextRunner.run( + (context) -> assertThat(context).doesNotHaveBean(RestClient.class) + .hasSingleBean(RestHighLevelClient.class)); + this.contextRunner.run( + (context) -> { + assertThat(context).hasSingleBean(Sniffer.class); + Sniffer sniffer = context.getBean(Sniffer.class); + Assert.assertNotNull(sniffer); + }); + } + + @Test + void configureWithCustomSetIntervalProperties() { + this.contextRunner.withPropertyValues("spring.elasticsearch.sniff.sniffInterval=15s, " + + "spring.elasticsearch.sniff.sniffFailureDelay=15s").run((context) -> { + Sniffer sniffer = context.getBean(Sniffer.class); + Assert.assertNotNull(sniffer); + }); + } + @Configuration(proxyBeanMethods = false) static class BuilderCustomizerConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java deleted file mode 100644 index 88e554af8da7..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/sniff/ElasticsearchSnifferAutoConfigurationTests.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.boot.autoconfigure.elasticsearch.sniff; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; -import org.assertj.core.api.InstanceOfAssertFactories; -import org.elasticsearch.action.get.GetRequest; -import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.client.*; -import org.elasticsearch.client.sniff.ElasticsearchNodesSniffer; -import org.elasticsearch.client.sniff.NodesSniffer; -import org.elasticsearch.client.sniff.Sniffer; -import org.elasticsearch.client.sniff.SnifferBuilder; -import org.junit.jupiter.api.Test; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.elasticsearch.sniff.SnifferBuilderCustomizer; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.boot.testsupport.testcontainers.DockerImageNames; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.testcontainers.elasticsearch.ElasticsearchContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import java.io.IOException; -import java.time.Duration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link org.springframework.boot.autoconfigure.elasticsearch.sniff.ElasticsearchSnifferAutoConfiguration}. - * - * @author Asha Somayajula - */ -@Testcontainers(disabledWithoutDocker = true) -class ElasticsearchSnifferAutoConfigurationTests { - - @Container - static final ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch()) - .withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10)); - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class)); - - @Test - void configureShouldOnlyCreateSnifferInstance() { - this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RestClient.class) - .hasSingleBean(RestHighLevelClient.class)); - this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Sniffer.class)); - } - - @Configuration(proxyBeanMethods = false) - static class BuilderCustomizerConfiguration { - - @Bean - SnifferBuilderCustomizer myCustomizer() { - return new SnifferBuilderCustomizer() { - - @Override - public void customize(SnifferBuilder builder) { - builder.setSniffAfterFailureDelayMillis(100); - builder.setSniffIntervalMillis(100); - NodesSniffer nodesSniffer = new NodesSniffer() { - @Override - public List sniff() throws IOException { - return null; - } - }; - - builder.setNodesSniffer(nodesSniffer); - } - }; - }; - } - } From 9ca5436864bcba69c2f242b5b4c43a1db9bba028 Mon Sep 17 00:00:00 2001 From: ashasomayajula Date: Tue, 22 Dec 2020 07:46:01 -0600 Subject: [PATCH 3/4] Fixes per review. --- ...sticsearchRestClientAutoConfiguration.java | 11 ++-- .../ElasticsearchRestClientProperties.java | 23 ++++++++ .../ElasticsearchSnifferProperties.java | 57 ------------------- ...sSnifferAvailableOnClasspathCondition.java | 21 +++++++ ...earchRestClientAutoConfigurationTests.java | 26 +++++++-- 5 files changed, 71 insertions(+), 67 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java index b4979bb71d7c..1734931b0758 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java @@ -41,6 +41,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; @@ -84,14 +85,16 @@ RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperti } @Bean - Sniffer elasticsearchSnifferBuilder(ElasticsearchSnifferProperties properties, + @Conditional(IsSnifferAvailableOnClasspathCondition.class) + @ConditionalOnMissingBean(RestHighLevelClient.class) + Sniffer elasticsearchSnifferBuilder(ElasticsearchRestClientProperties properties, RestClient elasticSearchRestClient) { return Sniffer.builder(elasticSearchRestClient) .setSniffIntervalMillis( - Math.toIntExact(properties.getSniffInterval().getSeconds() * 1000)) + Math.toIntExact(properties.getSniffInterval().toMillis())) .setSniffAfterFailureDelayMillis( - Math.toIntExact(properties.getSniffFailureDelay().getSeconds() * 1000)) - .build(); + Math.toIntExact(properties.getSniffFailureDelay().toMillis())) + .build(); } private HttpHost createHttpHost(String uri) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java index 1cc76ff8a4dd..eed61220eccc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java @@ -56,6 +56,14 @@ public class ElasticsearchRestClientProperties { * Read timeout. */ private Duration readTimeout = Duration.ofSeconds(30); + /** + * Sniffer interval + */ + private Duration sniffInterval = Duration.ofMinutes(5L); + /** + * Sniffer failure delay. + */ + private Duration sniffFailureDelay = Duration.ofMinutes(1L); public List getUris() { return this.uris; @@ -97,4 +105,19 @@ public void setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout; } + public Duration getSniffInterval() { + return sniffInterval; + } + + public void setSniffInterval(Duration sniffInterval) { + this.sniffInterval = sniffInterval; + } + + public Duration getSniffFailureDelay() { + return sniffFailureDelay; + } + + public void setSniffFailureDelay(Duration sniffFailureDelay) { + this.sniffFailureDelay = sniffFailureDelay; + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java deleted file mode 100644 index a547f2b56ce7..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchSnifferProperties.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.boot.autoconfigure.elasticsearch; - -import org.elasticsearch.client.sniff.NodesSniffer; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * - */ -@ConfigurationProperties(prefix = "spring.elasticsearch.sniff") -public class ElasticsearchSnifferProperties { - - /** - * Sniffer interval - */ - private Duration sniffInterval = Duration.ofMinutes(5L); - /** - * Sniffer failure delay. - */ - private Duration sniffFailureDelay = Duration.ofMinutes(1L); - - public Duration getSniffInterval() { - return sniffInterval; - } - - public void setSniffInterval(Duration sniffInterval) { - this.sniffInterval = sniffInterval; - } - - public Duration getSniffFailureDelay() { - return sniffFailureDelay; - } - - public void setSniffFailureDelay(Duration sniffFailureDelay) { - this.sniffFailureDelay = sniffFailureDelay; - } -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java new file mode 100644 index 000000000000..47dd62c8fc46 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java @@ -0,0 +1,21 @@ +package org.springframework.boot.autoconfigure.elasticsearch; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +public class IsSnifferAvailableOnClasspathCondition implements Condition { + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return isSnifferJarOnClasspath(); + } + private boolean isSnifferJarOnClasspath() + { + try { + Class.forName("org.elasticsearch.client.sniff.Sniffer"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java index 1dab5e8874db..6586a58ca4b1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java @@ -243,20 +243,34 @@ void configureShouldHaveSnifferInstance() { this.contextRunner.run( (context) -> { assertThat(context).hasSingleBean(Sniffer.class); - Sniffer sniffer = context.getBean(Sniffer.class); - Assert.assertNotNull(sniffer); + Assert.assertNotNull(context.getBean(Sniffer.class)); }); } @Test void configureWithCustomSetIntervalProperties() { - this.contextRunner.withPropertyValues("spring.elasticsearch.sniff.sniffInterval=15s, " + - "spring.elasticsearch.sniff.sniffFailureDelay=15s").run((context) -> { - Sniffer sniffer = context.getBean(Sniffer.class); - Assert.assertNotNull(sniffer); + this.contextRunner.withPropertyValues("spring.elasticsearch.rest.sniffInterval=15s, " + + "spring.elasticsearch.rest.sniffFailureDelay=15s").run((context) -> { + Assert.assertNotNull(context.getBean(Sniffer.class)); }); } + @Test + void configureWithNoAutoConfigurationPropertySet() { + this.contextRunner.run((context) -> { + assertThat(context).doesNotHaveBean(Sniffer.class); + Assert.assertNull(context.getBean(Sniffer.class)); + }); + } + + @Test + void configureWhenCustomSnifferWhenPresent() { + this.contextRunner.withBean("customSniffer", Sniffer.class, () -> mock(Sniffer.class)) + .run((context) -> assertThat(context).hasSingleBean(RestHighLevelClient.class) + .hasSingleBean(Sniffer.class).hasBean("customSniffer")); + } + + @Configuration(proxyBeanMethods = false) static class BuilderCustomizerConfiguration { From c7932c31c43184fb3f5a8acbb09a24146a236e6b Mon Sep 17 00:00:00 2001 From: ashasomayajula Date: Wed, 23 Dec 2020 08:38:14 -0600 Subject: [PATCH 4/4] Fixes per review. --- ...sticsearchRestClientAutoConfiguration.java | 20 +++--- .../ElasticsearchRestClientProperties.java | 50 +++++++++------ ...sSnifferAvailableOnClasspathCondition.java | 21 ------- ...earchRestClientAutoConfigurationTests.java | 63 +++++++++---------- 4 files changed, 68 insertions(+), 86 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java index 1734931b0758..f10aec8aae75 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfiguration.java @@ -19,7 +19,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; -import java.time.temporal.TemporalUnit; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -31,9 +30,8 @@ import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; - import org.elasticsearch.client.sniff.Sniffer; -import org.elasticsearch.client.sniff.SnifferBuilder; + import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -41,7 +39,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; @@ -85,16 +82,17 @@ RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperti } @Bean - @Conditional(IsSnifferAvailableOnClasspathCondition.class) + @ConditionalOnClass(name = "org.elasticsearch.client.sniff.Sniffer") @ConditionalOnMissingBean(RestHighLevelClient.class) - Sniffer elasticsearchSnifferBuilder(ElasticsearchRestClientProperties properties, - RestClient elasticSearchRestClient) { - return Sniffer.builder(elasticSearchRestClient) + Sniffer elasticsearchSniffer(ElasticsearchRestClientProperties properties) { + RestClient restClient = new RestHighLevelClient(this.elasticsearchRestClientBuilder(properties, null)) + .getLowLevelClient(); + return Sniffer.builder(restClient) .setSniffIntervalMillis( - Math.toIntExact(properties.getSniffInterval().toMillis())) + Math.toIntExact(ElasticsearchRestClientProperties.Sniffer.getSniffInterval().toMillis())) .setSniffAfterFailureDelayMillis( - Math.toIntExact(properties.getSniffFailureDelay().toMillis())) - .build(); + Math.toIntExact(ElasticsearchRestClientProperties.Sniffer.getSniffInterval().toMillis())) + .build(); } private HttpHost createHttpHost(String uri) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java index eed61220eccc..13d8d11a2309 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientProperties.java @@ -56,14 +56,6 @@ public class ElasticsearchRestClientProperties { * Read timeout. */ private Duration readTimeout = Duration.ofSeconds(30); - /** - * Sniffer interval - */ - private Duration sniffInterval = Duration.ofMinutes(5L); - /** - * Sniffer failure delay. - */ - private Duration sniffFailureDelay = Duration.ofMinutes(1L); public List getUris() { return this.uris; @@ -105,19 +97,39 @@ public void setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout; } - public Duration getSniffInterval() { - return sniffInterval; - } + /** + * Sniffer specific properties. + */ + public static class Sniffer { - public void setSniffInterval(Duration sniffInterval) { - this.sniffInterval = sniffInterval; - } + private Duration readTimeout = Duration.ofSeconds(30); - public Duration getSniffFailureDelay() { - return sniffFailureDelay; - } + /** + * Sniffer interval. + */ + private static Duration sniffInterval = Duration.ofMinutes(5L); + + /** + * Sniffer failure delay. + */ + private static Duration sniffFailureDelay = Duration.ofMinutes(1L); + + public static Duration getSniffInterval() { + return sniffInterval; + } + + public void setSniffInterval(Duration sniffInterval) { + Sniffer.sniffInterval = sniffInterval; + } + + public static Duration getSniffFailureDelay() { + return sniffFailureDelay; + } + + public void setSniffFailureDelay(Duration sniffFailureDelay) { + Sniffer.sniffFailureDelay = sniffFailureDelay; + } - public void setSniffFailureDelay(Duration sniffFailureDelay) { - this.sniffFailureDelay = sniffFailureDelay; } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java deleted file mode 100644 index 47dd62c8fc46..000000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/IsSnifferAvailableOnClasspathCondition.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.springframework.boot.autoconfigure.elasticsearch; - -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.type.AnnotatedTypeMetadata; - -public class IsSnifferAvailableOnClasspathCondition implements Condition { - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - return isSnifferJarOnClasspath(); - } - private boolean isSnifferJarOnClasspath() - { - try { - Class.forName("org.elasticsearch.client.sniff.Sniffer"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java index 6586a58ca4b1..ff35472303dd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java @@ -16,12 +16,6 @@ package org.springframework.boot.autoconfigure.elasticsearch; -import java.io.IOException; -import java.time.Duration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.Credentials; @@ -31,25 +25,22 @@ import org.assertj.core.api.InstanceOfAssertFactories; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.index.IndexRequest; -import org.elasticsearch.client.Node; -import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.RestClient; -import org.elasticsearch.client.RestClientBuilder; -import org.elasticsearch.client.RestHighLevelClient; -import org.elasticsearch.client.sniff.NodesSniffer; +import org.elasticsearch.client.*; import org.elasticsearch.client.sniff.Sniffer; -import org.elasticsearch.client.sniff.SnifferBuilder; import org.junit.Assert; import org.junit.jupiter.api.Test; -import org.testcontainers.elasticsearch.ElasticsearchContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.testcontainers.DockerImageNames; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -228,31 +219,34 @@ void configureUriWithUsernameAndPasswordWhenUsernameAndPasswordPropertiesSet() { @Test void configureShouldOnlyCreateSnifferInstance() { - this.contextRunner.run( - (context) -> assertThat(context).doesNotHaveBean(RestClient.class) - .hasSingleBean(RestHighLevelClient.class)); - this.contextRunner.run( - (context) -> assertThat(context).hasSingleBean(Sniffer.class)); + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(Sniffer.class); + assertThat(context).doesNotHaveBean(RestClient.class).hasSingleBean(RestHighLevelClient.class); + }); } @Test void configureShouldHaveSnifferInstance() { - this.contextRunner.run( - (context) -> assertThat(context).doesNotHaveBean(RestClient.class) - .hasSingleBean(RestHighLevelClient.class)); - this.contextRunner.run( - (context) -> { - assertThat(context).hasSingleBean(Sniffer.class); - Assert.assertNotNull(context.getBean(Sniffer.class)); - }); + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(Sniffer.class); + assertThat(context).doesNotHaveBean(RestClient.class).hasSingleBean(RestHighLevelClient.class); + Assert.assertNotNull(context.getBean(Sniffer.class)); + }); } @Test void configureWithCustomSetIntervalProperties() { - this.contextRunner.withPropertyValues("spring.elasticsearch.rest.sniffInterval=15s, " + - "spring.elasticsearch.rest.sniffFailureDelay=15s").run((context) -> { - Assert.assertNotNull(context.getBean(Sniffer.class)); - }); + this.contextRunner.withPropertyValues( + "spring.elasticsearch.rest.sniffInterval=1m, " + "spring.elasticsearch.rest.sniffFailureDelay=1m") + .run((context) -> { + Assert.assertNotNull(context.getBean(Sniffer.class)); + assertThat(context).hasSingleBean(RestHighLevelClient.class); + RestHighLevelClient restClient = context.getBean(RestHighLevelClient.class); + assertThat(restClient.getLowLevelClient()).extracting("spring.elasticsearch.rest.sniffInterval") + .isEqualTo(Math.toIntExact(Duration.ofMinutes(1L).toMillis())); + assertThat(restClient.getLowLevelClient()).extracting("spring.elasticsearch.rest.sniffFailureDelay") + .isEqualTo(Math.toIntExact(Duration.ofMinutes(1L).toMillis())); + }); } @Test @@ -270,7 +264,6 @@ void configureWhenCustomSnifferWhenPresent() { .hasSingleBean(Sniffer.class).hasBean("customSniffer")); } - @Configuration(proxyBeanMethods = false) static class BuilderCustomizerConfiguration {