diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index c9864fd57f..e51abb7c1f 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -110,6 +110,11 @@ reactor-spring-context true + + io.searchbox + jest + true + org.flywaydb flyway-core diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestAutoConfiguration.java new file mode 100644 index 0000000000..9ac19e1dd2 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestAutoConfiguration.java @@ -0,0 +1,80 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.jest; + +import com.google.gson.Gson; +import io.searchbox.client.JestClient; +import io.searchbox.client.JestClientFactory; +import io.searchbox.client.config.HttpClientConfig; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +/** + * {@link EnableAutoConfiguration Auto-Configuration} for Jest. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@ConditionalOnClass(JestClient.class) +@EnableConfigurationProperties(JestProperties.class) +@AutoConfigureAfter(GsonAutoConfiguration.class) +public class JestAutoConfiguration { + + private final JestProperties properties; + + private final ObjectProvider gsonProvider; + + public JestAutoConfiguration(JestProperties properties, ObjectProvider gsonProvider) { + this.properties = properties; + this.gsonProvider = gsonProvider; + } + + @Bean + @ConditionalOnMissingBean + public JestClient jestClient() { + JestClientFactory factory = new JestClientFactory(); + factory.setHttpClientConfig(createHttpClientConfig()); + return factory.getObject(); + } + + protected HttpClientConfig createHttpClientConfig() { + HttpClientConfig.Builder builder = new HttpClientConfig + .Builder(this.properties.getUris()); + if (StringUtils.hasText(this.properties.getUsername())) { + builder.defaultCredentials(this.properties.getUsername(), + this.properties.getPassword()); + } + Gson gson = this.gsonProvider.getIfUnique(); + if (gson != null) { + builder.gson(gson); + } + return builder.connTimeout(this.properties.getConnectionTimeout()) + .readTimeout(this.properties.getReadTimeout()) + .build(); + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestProperties.java new file mode 100644 index 0000000000..445862f5c0 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jest/JestProperties.java @@ -0,0 +1,98 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.jest; + +import java.util.Collections; +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Jest. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@ConfigurationProperties("spring.jest") +public class JestProperties { + + /** + * Comma-separated list of the elasticsearch instances to use. + */ + private List uris = Collections.singletonList("http://localhost:9200"); + + /** + * Login user. + */ + private String username; + + /** + * Login password. + */ + private String password; + + /** + * Connection timeout in milliseconds. + */ + private int connectionTimeout = 3000; + + /** + * Read timeout in milliseconds. + */ + private int readTimeout = 3000; + + public List getUris() { + return this.uris; + } + + public void setUris(List uris) { + this.uris = uris; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getConnectionTimeout() { + return this.connectionTimeout; + } + + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public int getReadTimeout() { + return this.readTimeout; + } + + public void setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + } + +} diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 189675065e..1987c85141 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -50,6 +50,7 @@ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\ +org.springframework.boot.autoconfigure.jest.JestAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jest/JestAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jest/JestAutoConfigurationTests.java new file mode 100644 index 0000000000..319875426c --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jest/JestAutoConfigurationTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.jest; + +import com.google.gson.Gson; +import io.searchbox.client.JestClient; +import io.searchbox.client.http.JestHttpClient; +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link JestAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class JestAutoConfigurationTests { + + protected AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void jestClientOnLocalhostByDefault() { + load(); + assertThat(this.context.getBeansOfType(JestClient.class)).hasSize(1); + } + + @Test + public void customJestClient() { + load(CustomJestClient.class, "spring.jest.uris=http://localhost:9200"); + assertThat(this.context.getBeansOfType(JestClient.class)).hasSize(1); + } + + @Test + public void customGson() { + load(CustomGson.class, "spring.jest.uris=http://localhost:9200"); + JestHttpClient client = (JestHttpClient) this.context.getBean(JestClient.class); + assertThat(client.getGson()).isSameAs(this.context.getBean("customGson")); + } + + private void load(String... environment) { + load(null, environment); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(context, environment); + if (config != null) { + context.register(config); + } + context.register(GsonAutoConfiguration.class, JestAutoConfiguration.class); + context.refresh(); + this.context = context; + } + + @Configuration + static class CustomJestClient { + + @Bean + public JestClient customJestClient() { + return mock(JestClient.class); + } + + } + + @Configuration + static class CustomGson { + + @Bean + public Gson customGson() { + return new Gson(); + } + + } + +} diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 305a2fc84d..4d08989362 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -106,6 +106,7 @@ 2.0.6 2.8.1 2.23 + 2.0.3 9.2.17.v20160517 2.2.0.v201112011158 1.12 @@ -928,6 +929,11 @@ reactor-spring-webmvc ${reactor-spring.version} + + io.searchbox + jest + ${jest.version} + io.undertow undertow-core diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index ee073d253a..9a51d5b26a 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -629,6 +629,13 @@ content into your application; rather pick only the properties that you need. spring.h2.console.settings.trace=false # Enable trace output. spring.h2.console.settings.web-allow-others=false # Enable remote access. + # JEST (ElasticSearch HTTP client) ({sc-spring-boot-autoconfigure}/jest/JestProperties.{sc-ext}[JestProperties]) + spring.jest.connection-timeout=3000 # Connection timeout in milliseconds. + spring.jest.password= # Login password. + spring.jest.read-timeout=3000 # Read timeout in milliseconds. + spring.jest.uris=http://localhost:9200 # Comma-separated list of the elasticsearch instances to use. + spring.jest.username= # Login user. + # JOOQ ({sc-spring-boot-autoconfigure}/jooq/JooqAutoConfiguration.{sc-ext}[JooqAutoConfiguration]) spring.jooq.sql-dialect= # SQLDialect JOOQ used when communicating with the configured datasource. For instance `POSTGRES` diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index e1b3d3bbe0..8351092600 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3315,12 +3315,31 @@ real-time search and analytics engine. Spring Boot offers basic auto-configurati the Elasticsearch and abstractions on top of it provided by https://github.com/spring-projects/spring-data-elasticsearch[Spring Data Elasticsearch]. There is a `spring-boot-starter-data-elasticsearch` '`Starter`' for collecting the -dependencies in a convenient way. +dependencies in a convenient way. Spring Boot also supports +https://github.com/searchbox-io/Jest[Jest]. +[[boot-features-connecting-to-elasticsearch-jest]] +==== Connecting to Elasticsearch using Spring Data +If you have `Jest` on the classpath, you can inject an auto-configured `JestClient` +targeting `http://localhost:9200` by default. You can further tune how the client is +configured: + +[source,properties,indent=0] +---- + spring.jest.uris=http://search.example.com:9200 + spring.jest.read-timeout=10000 + spring.jest.username=user + spring.jest.password=secret +---- + +To take full control over the registration, define a `JestClient` bean. + + [[boot-features-connecting-to-elasticsearch]] -==== Connecting to Elasticsearch +[[boot-features-connecting-to-elasticsearch-spring-data]] +==== Connecting to Elasticsearch using Spring Data You can inject an auto-configured `ElasticsearchTemplate` or Elasticsearch `Client` instance as you would any other Spring Bean. By default the instance will embed a local in-memory server (a `Node` in ElasticSearch terms) and use the current working