diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java index 7beb5a601b8b..095c8e5f3e5a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfiguration.java @@ -39,10 +39,9 @@ * @author Artsiom Yudovin * @since 2.1.1 */ -@SuppressWarnings("deprecation") @AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class) -@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class) -@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class) +@ConditionalOnClass(RestClient.class) +@ConditionalOnBean(RestClient.class) @ConditionalOnEnabledHealthIndicator("elasticsearch") public class ElasticSearchRestHealthContributorAutoConfiguration extends CompositeHealthContributorConfiguration { @@ -53,4 +52,4 @@ public HealthContributor elasticsearchHealthContributor(Map return createContributor(clients); } -} \ No newline at end of file +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorConfigurations.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorConfigurations.java deleted file mode 100644 index 948a3c2ca3c6..000000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorConfigurations.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2012-2022 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.actuate.autoconfigure.elasticsearch; - -import java.util.Map; - -import org.elasticsearch.client.RestClient; - -import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration; -import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator; -import org.springframework.boot.actuate.health.HealthContributor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Elasticsearch rest client health contributor configurations. - * - * @author Filip Hrisafov - */ -class ElasticSearchRestHealthContributorConfigurations { - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class) - @ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class) - @Deprecated - static class RestHighLevelClientHealthContributorConfiguration extends - CompositeHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) - HealthContributor elasticsearchHealthContributor( - Map clients) { - return createContributor(clients); - } - - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnBean(RestClient.class) - @ConditionalOnMissingBean(org.elasticsearch.client.RestHighLevelClient.class) - static class RestClientHealthContributorConfiguration - extends CompositeHealthContributorConfiguration { - - @Bean - @ConditionalOnMissingBean(name = { "elasticsearchHealthIndicator", "elasticsearchHealthContributor" }) - HealthContributor elasticsearchHealthContributor(Map clients) { - return createContributor(clients); - } - - } - -} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfigurationTests.java similarity index 87% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfigurationTests.java index 0a3418329f22..56972fc4ba43 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchRestHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticSearchRestHealthContributorAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration; -import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator; import org.springframework.boot.actuate.elasticsearch.ElasticsearchRestHealthIndicator; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; @@ -33,11 +32,12 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link ElasticsearchRestClientAutoConfiguration}. + * Tests for {@link ElasticSearchRestHealthContributorAutoConfiguration}. * * @author Filip Hrisafov + * @author Andy Wilkinson */ -class ElasticsearchRestHealthContributorAutoConfigurationTests { +class ElasticSearchRestHealthContributorAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class, @@ -45,42 +45,40 @@ class ElasticsearchRestHealthContributorAutoConfigurationTests { HealthContributorAutoConfiguration.class)); @Test - @SuppressWarnings("deprecation") void runShouldCreateIndicator() { this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestHealthIndicator.class) .hasBean("elasticsearchHealthContributor")); } @Test + @SuppressWarnings("deprecation") void runWithoutRestHighLevelClientAndWithoutRestClientShouldNotCreateIndicator() { this.contextRunner .withClassLoader( new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class, RestClient.class)) - .run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class) + .run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestHealthIndicator.class) .doesNotHaveBean("elasticsearchHealthContributor")); } @Test - @SuppressWarnings("deprecation") void runWithoutRestHighLevelClientAndWithRestClientShouldCreateIndicator() { this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class) - .doesNotHaveBean(ElasticsearchRestHealthIndicator.class) + .run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestHealthIndicator.class) + .hasSingleBean(ElasticsearchRestHealthIndicator.class) .hasBean("elasticsearchHealthContributor")); } @Test - @SuppressWarnings("deprecation") void runWithRestHighLevelClientAndWithRestClientShouldCreateIndicator() { this.contextRunner.withUserConfiguration(CustomRestHighClientConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class) + .run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestHealthIndicator.class) .hasBean("elasticsearchHealthContributor")); } @Test void runWhenDisabledShouldNotCreateIndicator() { this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false") - .run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class) + .run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestHealthIndicator.class) .doesNotHaveBean("elasticsearchHealthContributor")); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java index 0c81b6af6508..c14fc96e4f62 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/elasticsearch/ElasticsearchReactiveHealthContributorAutoConfigurationTests.java @@ -50,7 +50,6 @@ void runShouldCreateIndicator() { } @Test - @SuppressWarnings("deprecation") void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() { this.contextRunner .withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class)) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicator.java deleted file mode 100644 index da0821e14385..000000000000 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicator.java +++ /dev/null @@ -1,85 +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.actuate.elasticsearch; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; - -import org.apache.http.HttpStatus; -import org.apache.http.StatusLine; -import org.elasticsearch.client.Request; -import org.elasticsearch.client.Response; -import org.elasticsearch.client.RestClient; - -import org.springframework.boot.actuate.health.AbstractHealthIndicator; -import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.boot.json.JsonParser; -import org.springframework.boot.json.JsonParserFactory; -import org.springframework.util.StreamUtils; - -/** - * {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}. - * - * @author Artsiom Yudovin - * @author Brian Clozel - * @author Filip Hrisafov - * @since 2.7 - */ -public class ElasticsearchRestClientHealthIndicator extends AbstractHealthIndicator { - - private static final String RED_STATUS = "red"; - - private final RestClient client; - - private final JsonParser jsonParser; - - public ElasticsearchRestClientHealthIndicator(RestClient client) { - super("Elasticsearch health check failed"); - this.client = client; - this.jsonParser = JsonParserFactory.getJsonParser(); - } - - @Override - protected void doHealthCheck(Health.Builder builder) throws Exception { - Response response = this.client.performRequest(new Request("GET", "/_cluster/health/")); - StatusLine statusLine = response.getStatusLine(); - if (statusLine.getStatusCode() != HttpStatus.SC_OK) { - builder.down(); - builder.withDetail("statusCode", statusLine.getStatusCode()); - builder.withDetail("reasonPhrase", statusLine.getReasonPhrase()); - return; - } - try (InputStream inputStream = response.getEntity().getContent()) { - doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8)); - } - } - - private void doHealthCheck(Health.Builder builder, String json) { - Map response = this.jsonParser.parseMap(json); - String status = (String) response.get("status"); - if (RED_STATUS.equals(status)) { - builder.outOfService(); - } - else { - builder.up(); - } - builder.withDetails(response); - } - -} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java index 596018ed168c..468f235c3b18 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java @@ -16,9 +16,22 @@ package org.springframework.boot.actuate.elasticsearch; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.boot.json.JsonParser; +import org.springframework.boot.json.JsonParserFactory; +import org.springframework.util.StreamUtils; /** * {@link HealthIndicator} for an Elasticsearch cluster using a {@link RestClient}. @@ -27,11 +40,14 @@ * @author Brian Clozel * @author Filip Hrisafov * @since 2.1.1 - * @deprecated since 2.7.0 for removal in 2.9.0 in favor of - * {@link ElasticsearchRestClientHealthIndicator} */ -@Deprecated -public class ElasticsearchRestHealthIndicator extends ElasticsearchRestClientHealthIndicator { +public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator { + + private static final String RED_STATUS = "red"; + + private final RestClient client; + + private final JsonParser jsonParser; @SuppressWarnings("deprecation") public ElasticsearchRestHealthIndicator(org.elasticsearch.client.RestHighLevelClient client) { @@ -39,7 +55,36 @@ public ElasticsearchRestHealthIndicator(org.elasticsearch.client.RestHighLevelCl } public ElasticsearchRestHealthIndicator(RestClient client) { - super(client); + super("Elasticsearch health check failed"); + this.client = client; + this.jsonParser = JsonParserFactory.getJsonParser(); + } + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + Response response = this.client.performRequest(new Request("GET", "/_cluster/health/")); + StatusLine statusLine = response.getStatusLine(); + if (statusLine.getStatusCode() != HttpStatus.SC_OK) { + builder.down(); + builder.withDetail("statusCode", statusLine.getStatusCode()); + builder.withDetail("reasonPhrase", statusLine.getReasonPhrase()); + return; + } + try (InputStream inputStream = response.getEntity().getContent()) { + doHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8)); + } + } + + private void doHealthCheck(Health.Builder builder, String json) { + Map response = this.jsonParser.parseMap(json); + String status = (String) response.get("status"); + if (RED_STATUS.equals(status)) { + builder.outOfService(); + } + else { + builder.up(); + } + builder.withDetails(response); } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicatorTests.java deleted file mode 100644 index 80550160b055..000000000000 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestClientHealthIndicatorTests.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2012-2019 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.actuate.elasticsearch; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Map; - -import org.apache.http.StatusLine; -import org.apache.http.entity.BasicHttpEntity; -import org.elasticsearch.client.Request; -import org.elasticsearch.client.Response; -import org.elasticsearch.client.RestClient; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.actuate.health.Health; -import org.springframework.boot.actuate.health.Status; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link ElasticsearchRestClientHealthIndicator}. - * - * @author Artsiom Yudovin - * @author Filip Hrisafov - */ -class ElasticsearchRestClientHealthIndicatorTests { - - private final RestClient restClient = mock(RestClient.class); - - private final ElasticsearchRestClientHealthIndicator elasticsearchRestHealthIndicator = new ElasticsearchRestClientHealthIndicator( - this.restClient); - - @Test - void elasticsearchIsUp() throws IOException { - BasicHttpEntity httpEntity = new BasicHttpEntity(); - httpEntity.setContent(new ByteArrayInputStream(createJsonResult(200, "green").getBytes())); - Response response = mock(Response.class); - StatusLine statusLine = mock(StatusLine.class); - given(statusLine.getStatusCode()).willReturn(200); - given(response.getStatusLine()).willReturn(statusLine); - given(response.getEntity()).willReturn(httpEntity); - given(this.restClient.performRequest(any(Request.class))).willReturn(response); - Health health = this.elasticsearchRestHealthIndicator.health(); - assertThat(health.getStatus()).isEqualTo(Status.UP); - assertHealthDetailsWithStatus(health.getDetails(), "green"); - } - - @Test - void elasticsearchWithYellowStatusIsUp() throws IOException { - BasicHttpEntity httpEntity = new BasicHttpEntity(); - httpEntity.setContent(new ByteArrayInputStream(createJsonResult(200, "yellow").getBytes())); - Response response = mock(Response.class); - StatusLine statusLine = mock(StatusLine.class); - given(statusLine.getStatusCode()).willReturn(200); - given(response.getStatusLine()).willReturn(statusLine); - given(response.getEntity()).willReturn(httpEntity); - given(this.restClient.performRequest(any(Request.class))).willReturn(response); - Health health = this.elasticsearchRestHealthIndicator.health(); - assertThat(health.getStatus()).isEqualTo(Status.UP); - assertHealthDetailsWithStatus(health.getDetails(), "yellow"); - } - - @Test - void elasticsearchIsDown() throws IOException { - given(this.restClient.performRequest(any(Request.class))).willThrow(new IOException("Couldn't connect")); - Health health = this.elasticsearchRestHealthIndicator.health(); - assertThat(health.getStatus()).isEqualTo(Status.DOWN); - assertThat(health.getDetails()).contains(entry("error", "java.io.IOException: Couldn't connect")); - } - - @Test - void elasticsearchIsDownByResponseCode() throws IOException { - Response response = mock(Response.class); - StatusLine statusLine = mock(StatusLine.class); - given(statusLine.getStatusCode()).willReturn(500); - given(statusLine.getReasonPhrase()).willReturn("Internal server error"); - given(response.getStatusLine()).willReturn(statusLine); - given(this.restClient.performRequest(any(Request.class))).willReturn(response); - Health health = this.elasticsearchRestHealthIndicator.health(); - assertThat(health.getStatus()).isEqualTo(Status.DOWN); - assertThat(health.getDetails()).contains(entry("statusCode", 500), - entry("reasonPhrase", "Internal server error")); - } - - @Test - void elasticsearchIsOutOfServiceByStatus() throws IOException { - BasicHttpEntity httpEntity = new BasicHttpEntity(); - httpEntity.setContent(new ByteArrayInputStream(createJsonResult(200, "red").getBytes())); - Response response = mock(Response.class); - StatusLine statusLine = mock(StatusLine.class); - given(statusLine.getStatusCode()).willReturn(200); - given(response.getStatusLine()).willReturn(statusLine); - given(response.getEntity()).willReturn(httpEntity); - given(this.restClient.performRequest(any(Request.class))).willReturn(response); - Health health = this.elasticsearchRestHealthIndicator.health(); - assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE); - assertHealthDetailsWithStatus(health.getDetails(), "red"); - } - - private void assertHealthDetailsWithStatus(Map details, String status) { - assertThat(details).contains(entry("cluster_name", "elasticsearch"), entry("status", status), - entry("timed_out", false), entry("number_of_nodes", 1), entry("number_of_data_nodes", 1), - entry("active_primary_shards", 0), entry("active_shards", 0), entry("relocating_shards", 0), - entry("initializing_shards", 0), entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0), - entry("number_of_pending_tasks", 0), entry("number_of_in_flight_fetch", 0), - entry("task_max_waiting_in_queue_millis", 0), entry("active_shards_percent_as_number", 100.0)); - } - - private String createJsonResult(int responseCode, String status) { - if (responseCode == 200) { - return String.format( - "{\"cluster_name\":\"elasticsearch\"," - + "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1," - + "\"number_of_data_nodes\":1,\"active_primary_shards\":0," - + "\"active_shards\":0,\"relocating_shards\":0,\"initializing_shards\":0," - + "\"unassigned_shards\":0,\"delayed_unassigned_shards\":0," - + "\"number_of_pending_tasks\":0,\"number_of_in_flight_fetch\":0," - + "\"task_max_waiting_in_queue_millis\":0,\"active_shards_percent_as_number\":100.0}", - status); - } - return "{\n \"error\": \"Server Error\",\n \"status\": " + responseCode + "\n}"; - } - -} diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicatorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicatorTests.java index 8312fb5dbbb5..c283c049e2b3 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicatorTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicatorTests.java @@ -42,7 +42,6 @@ * @author Artsiom Yudovin * @author Filip Hrisafov */ -@Deprecated class ElasticsearchRestHealthIndicatorTests { private final RestClient restClient = mock(RestClient.class); 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 da462db9f242..db67b1f0d38a 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 @@ -23,8 +23,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientConfiguration; +import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientFromRestHighLevelClientConfiguration; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientSnifferConfiguration; -import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientWithRestHighLevelClientConfiguration; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestHighLevelClientConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; @@ -42,7 +42,7 @@ @EnableConfigurationProperties({ ElasticsearchProperties.class, ElasticsearchRestClientProperties.class, DeprecatedElasticsearchRestClientProperties.class }) @Import({ RestClientBuilderConfiguration.class, RestHighLevelClientConfiguration.class, - RestClientWithRestHighLevelClientConfiguration.class, RestClientConfiguration.class, + RestClientFromRestHighLevelClientConfiguration.class, RestClientConfiguration.class, RestClientSnifferConfiguration.class }) public class ElasticsearchRestClientAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java index d8ed7df41739..8e50a3da5ff6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java @@ -131,7 +131,7 @@ org.elasticsearch.client.RestHighLevelClient elasticsearchRestHighLevelClient( @ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class) @ConditionalOnSingleCandidate(org.elasticsearch.client.RestHighLevelClient.class) @ConditionalOnMissingBean(RestClient.class) - static class RestClientWithRestHighLevelClientConfiguration { + static class RestClientFromRestHighLevelClientConfiguration { @Bean RestClient elasticsearchRestClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationIntegrationTests.java index eb93f9979a22..e979c4d1d823 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationIntegrationTests.java @@ -35,7 +35,6 @@ import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.testsupport.testcontainers.DockerImageNames; @@ -97,24 +96,4 @@ void restClientCanQueryElasticsearchNode() { }); } - @Test - @SuppressWarnings("deprecation") - void restClientCanQueryElasticsearchNodeWithoutHighLevelClient() { - this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class)) - .withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(), - "spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s") - .run((context) -> { - RestClient client = context.getBean(RestClient.class); - Request index = new Request("PUT", "/test/_doc/3"); - index.setJsonEntity("{" + " \"a\": \"alpha\"," + " \"b\": \"bravo\"" + "}"); - client.performRequest(index); - Request getRequest = new Request("GET", "/test/_doc/3"); - Response response = client.performRequest(getRequest); - try (InputStream input = response.getEntity().getContent()) { - JsonNode result = new ObjectMapper().readTree(input); - assertThat(result.path("found").asBoolean()).isTrue(); - } - }); - } - } 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 6a34c51d50c3..11a8ee9f58e2 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 @@ -21,7 +21,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.time.Duration; -import java.util.Map; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; @@ -55,6 +54,7 @@ * @author Vedran Pavic * @author Evgeniy Cheban * @author Filip Hrisafov + * @author Andy Wilkinson */ @SuppressWarnings("deprecation") class ElasticsearchRestClientAutoConfigurationTests { @@ -63,7 +63,7 @@ class ElasticsearchRestClientAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class)); @Test - void configureShouldCreateHighLevelAndLowLevelRestClient() { + void configureShouldCreateHighLevelAndLowLevelRestClients() { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(RestClient.class) .hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class) @@ -77,8 +77,8 @@ void configureShouldCreateHighLevelAndLowLevelRestClient() { void configureWithoutRestHighLevelClientShouldOnlyCreateRestClientBuilderAndRestClient() { this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class)) .run((context) -> assertThat(context).hasSingleBean(RestClient.class) - .doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class) - .hasSingleBean(RestClientBuilder.class)); + .hasSingleBean(RestClientBuilder.class) + .doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class)); } @Test @@ -91,44 +91,26 @@ void configureWhenCustomRestClientShouldBackOff() { } @Test - void configureWhenCustomRestHighLevelClientIsNotPresent() { - this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class)) - .run((context) -> assertThat(context) - .doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class) - .hasSingleBean(RestClient.class).hasSingleBean(RestClientBuilder.class)); - } - - @Test - void configureWhenCustomRestHighLevelClientShouldBackOff() { + void configureWhenCustomRestHighLevelClientShouldDefineRestClientFromCustomHighLevelClient() { this.contextRunner.withUserConfiguration(CustomRestHighLevelClientConfiguration.class) .run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class) - .hasSingleBean(RestClient.class).hasBean("elasticsearchRestClient")); + .hasSingleBean(RestClient.class).hasBean("elasticsearchRestClient").getBean(RestClient.class) + .isEqualTo(context.getBean(org.elasticsearch.client.RestHighLevelClient.class) + .getLowLevelClient())); } @Test - void configureWhenCustomRestHighLevelClientAndRestClientWithRestHighLevelClientShouldBackOff() { + void configureWhenCustomRestHighLevelClientAndRestClientShouldBackOff() { this.contextRunner.withUserConfiguration(CustomRestHighLevelClientWithRestClientConfiguration.class) .run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class) - .hasSingleBean(RestClient.class).hasBean("customRestClient")); - } - - @Test - void configureWhenDefaultRestClientShouldCreateWhenNoUniqueRestHighLevelClient() { - this.contextRunner.withUserConfiguration(TwoCustomRestHighLevelClientConfiguration.class).run((context) -> { - assertThat(context).doesNotHaveBean(RestClient.class); - Map restHighLevelClients = context - .getBeansOfType(org.elasticsearch.client.RestHighLevelClient.class); - assertThat(restHighLevelClients).hasSize(2); - }); + .hasBean("customRestHighLevelClient").hasSingleBean(RestClient.class) + .hasBean("customRestClient")); } @Test - void configureWhenDefaultRestClientShouldCreateWhenNoUniqueRestClient() { - this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class)) - .withUserConfiguration(TwoCustomRestClientConfiguration.class).run((context) -> { - Map restClients = context.getBeansOfType(RestClient.class); - assertThat(restClients).hasSize(2); - }); + void configureWhenNoUniqueRestHighLevelClientShouldNotDefineRestClient() { + this.contextRunner.withUserConfiguration(TwoCustomRestHighLevelClientsConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(RestClient.class)); } @Test @@ -352,7 +334,7 @@ RestClient customRestClient(org.elasticsearch.client.RestHighLevelClient restHig } @Configuration(proxyBeanMethods = false) - static class TwoCustomRestHighLevelClientConfiguration { + static class TwoCustomRestHighLevelClientsConfiguration { @Bean org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) { @@ -360,7 +342,7 @@ org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClien } @Bean - org.elasticsearch.client.RestHighLevelClient customoRestHighLevelClient1(RestClientBuilder builder) { + org.elasticsearch.client.RestHighLevelClient anotherCustomRestHighLevelClient(RestClientBuilder builder) { return new org.elasticsearch.client.RestHighLevelClient(builder); } diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc index 9cc927f2bb90..122a91afe9bb 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc @@ -252,9 +252,8 @@ Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elastics [[data.nosql.elasticsearch.connecting-using-rest]] ==== Connecting to Elasticsearch using REST clients -Elasticsearch ships https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html[two different REST clients] that you can use to query a cluster: the "Low Level" client and the "High Level" client. -Spring Boot provides support for the "High Level" client, which ships with `org.elasticsearch.client:elasticsearch-rest-high-level-client`. -Additionally, Spring Boot provides support for a reactive client, based on Spring Framework's `WebClient`, that ships with `org.springframework.data:spring-data-elasticsearch`. +Elasticsearch ships https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html[two different REST clients] that you can use to query a cluster: the low-level client from the `org.elasticsearch.client:elasticsearch-rest-client` module and the high-level client from the `org.elasticsearch.client:elasticsearch-high-level-client` module. +Additionally, Spring Boot provides support for a reactive client, based on Spring Framework's `WebClient`, from the `org.springframework.data:spring-data-elasticsearch` module. By default, the clients will target `http://localhost:9200`. You can use `spring.elasticsearch.*` properties to further tune how the clients are configured, as shown in the following example: @@ -271,10 +270,11 @@ You can use `spring.elasticsearch.*` properties to further tune how the clients [[data.nosql.elasticsearch.connecting-using-rest.restclient]] ===== Connecting to Elasticsearch using RestClient If you have `elasticsearch-rest-client` on the classpath, Spring Boot will auto-configure and register a `RestClient` bean. -In addition to the properties described previously, to fine-tune the `RestClient`, you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations. -To take full control over its registration, define a `RestClientBuilder` bean. +If you have `elasticsearch-rest-high-level-client` on the classpath a `RestHighLevelClient` bean will be registered as well. +In addition to the properties described previously, to fine-tune the `RestClient` and `RestHighLevelClient`, you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations. +To take full control over the clients' configuration, define a `RestClientBuilder` bean. + -NOTE: If you have `elasticsearch-rest-high-level-client` on the classpath a `RestHighLevelClient` bean will be exposed as well Additionally, if `elasticsearch-rest-client-sniffer` is on the classpath, a `Sniffer` is auto-configured to automatically discover nodes from a running Elasticsearch cluster and set them on the `RestClient` bean. You can further tune how `Sniffer` is configured, as shown in the following example: