From 42762a66b86ea55760274036882a102f37798edf Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 31 May 2017 21:46:36 -0700 Subject: [PATCH] Upgrade to Elasticsearch 5.4.0 Upgrade to Elasticsearch 5.4.0 and fix auto-configuration to account for API changes. See gh-9374 --- .../ElasticsearchAutoConfiguration.java | 79 ++++++++++++++----- .../ElasticsearchAutoConfigurationTests.java | 16 ++-- spring-boot-dependencies/pom.xml | 7 +- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.java index d7f953ba1a..7fcf0fa377 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.java @@ -16,19 +16,23 @@ package org.springframework.boot.autoconfigure.data.elasticsearch; +import java.io.Closeable; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.elasticsearch.client.Client; import org.elasticsearch.client.transport.TransportClient; -import org.elasticsearch.common.lease.Releasable; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.node.InternalSettingsPreparer; import org.elasticsearch.node.Node; -import org.elasticsearch.node.NodeBuilder; +import org.elasticsearch.plugins.Plugin; import org.springframework.beans.factory.DisposableBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -38,7 +42,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.client.NodeClientFactoryBean; import org.springframework.data.elasticsearch.client.TransportClientFactoryBean; -import org.springframework.util.ReflectionUtils; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -61,17 +65,26 @@ public class ElasticsearchAutoConfiguration implements DisposableBean { static { Map defaults = new LinkedHashMap<>(); defaults.put("http.enabled", String.valueOf(false)); - defaults.put("node.local", String.valueOf(true)); + defaults.put("transport.type", "local"); defaults.put("path.home", System.getProperty("user.dir")); DEFAULTS = Collections.unmodifiableMap(defaults); } + private static final Set TRANSPORT_PLUGINS; + + static { + Set plugins = new LinkedHashSet<>(); + plugins.add("org.elasticsearch.transport.Netty4Plugin"); + plugins.add("org.elasticsearch.transport.Netty3Plugin"); + TRANSPORT_PLUGINS = Collections.unmodifiableSet(plugins); + } + private static final Log logger = LogFactory .getLog(ElasticsearchAutoConfiguration.class); private final ElasticsearchProperties properties; - private Releasable releasable; + private Closeable closeable; public ElasticsearchAutoConfiguration(ElasticsearchProperties properties) { this.properties = properties; @@ -96,26 +109,47 @@ public class ElasticsearchAutoConfiguration implements DisposableBean { } private Client createNodeClient() throws Exception { - Settings.Builder settings = Settings.settingsBuilder(); + Settings.Builder settings = Settings.builder(); for (Map.Entry entry : DEFAULTS.entrySet()) { if (!this.properties.getProperties().containsKey(entry.getKey())) { settings.put(entry.getKey(), entry.getValue()); } } settings.put(this.properties.getProperties()); - Node node = new NodeBuilder().settings(settings) - .clusterName(this.properties.getClusterName()).node(); - this.releasable = node; + settings.put("cluster.name", this.properties.getClusterName()); + Node node = createNode(settings.build()); + this.closeable = node; + node.start(); return node.client(); } + private Node createNode(Settings settings) { + Collection> plugins = findPlugins(); + if (plugins.isEmpty()) { + return new Node(settings); + } + return new PluggableNode(settings, plugins); + } + + @SuppressWarnings("unchecked") + private Collection> findPlugins() { + for (String candidate : TRANSPORT_PLUGINS) { + if (ClassUtils.isPresent(candidate, null)) { + Class pluginClass = (Class) ClassUtils + .resolveClassName(candidate, null); + return Collections.singleton(pluginClass); + } + } + return Collections.emptySet(); + } + private Client createTransportClient() throws Exception { TransportClientFactoryBean factory = new TransportClientFactoryBean(); factory.setClusterNodes(this.properties.getClusterNodes()); factory.setProperties(createProperties()); factory.afterPropertiesSet(); TransportClient client = factory.getObject(); - this.releasable = client; + this.closeable = client; return client; } @@ -128,20 +162,12 @@ public class ElasticsearchAutoConfiguration implements DisposableBean { @Override public void destroy() throws Exception { - if (this.releasable != null) { + if (this.closeable != null) { try { if (logger.isInfoEnabled()) { logger.info("Closing Elasticsearch client"); } - try { - this.releasable.close(); - } - catch (NoSuchMethodError ex) { - // Earlier versions of Elasticsearch had a different method name - ReflectionUtils.invokeMethod( - ReflectionUtils.findMethod(Releasable.class, "release"), - this.releasable); - } + this.closeable.close(); } catch (final Exception ex) { if (logger.isErrorEnabled()) { @@ -151,4 +177,17 @@ public class ElasticsearchAutoConfiguration implements DisposableBean { } } + /** + * {@link Node} subclass to support {@link Plugin Plugins}. + */ + private static class PluggableNode extends Node { + + PluggableNode(Settings preparedSettings, + Collection> classpathPlugins) { + super(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), + classpathPlugins); + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java index 1c9297b60b..4b762beddd 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java @@ -56,7 +56,7 @@ public class ElasticsearchAutoConfigurationTests { public void createNodeClientWithDefaults() { this.context = new AnnotationConfigApplicationContext(); TestPropertyValues - .of("spring.data.elasticsearch.properties.foo.bar:baz", + .of("spring.data.elasticsearch.properties.monitor.process.refresh_interval:2s", "spring.data.elasticsearch.properties.path.home:target") .applyTo(this.context); this.context.register(PropertyPlaceholderAutoConfiguration.class, @@ -64,8 +64,9 @@ public class ElasticsearchAutoConfigurationTests { this.context.refresh(); assertThat(this.context.getBeanNamesForType(Client.class).length).isEqualTo(1); NodeClient client = (NodeClient) this.context.getBean(Client.class); - assertThat(client.settings().get("foo.bar")).isEqualTo("baz"); - assertThat(client.settings().get("node.local")).isEqualTo("true"); + assertThat(client.settings().get("monitor.process.refresh_interval")) + .isEqualTo("2s"); + assertThat(client.settings().get("transport.type")).isEqualTo("local"); assertThat(client.settings().get("http.enabled")).isEqualTo("false"); } @@ -73,9 +74,9 @@ public class ElasticsearchAutoConfigurationTests { public void createNodeClientWithOverrides() { this.context = new AnnotationConfigApplicationContext(); TestPropertyValues - .of("spring.data.elasticsearch.properties.foo.bar:baz", + .of("spring.data.elasticsearch.properties.monitor.process.refresh_interval:2s", "spring.data.elasticsearch.properties.path.home:target", - "spring.data.elasticsearch.properties.node.local:false", + "spring.data.elasticsearch.properties.transport.type:local", "spring.data.elasticsearch.properties.node.data:true", "spring.data.elasticsearch.properties.http.enabled:true") .applyTo(this.context); @@ -84,8 +85,9 @@ public class ElasticsearchAutoConfigurationTests { this.context.refresh(); assertThat(this.context.getBeanNamesForType(Client.class).length).isEqualTo(1); NodeClient client = (NodeClient) this.context.getBean(Client.class); - assertThat(client.settings().get("foo.bar")).isEqualTo("baz"); - assertThat(client.settings().get("node.local")).isEqualTo("false"); + assertThat(client.settings().get("monitor.process.refresh_interval")) + .isEqualTo("2s"); + assertThat(client.settings().get("transport.type")).isEqualTo("local"); assertThat(client.settings().get("node.data")).isEqualTo("true"); assertThat(client.settings().get("http.enabled")).isEqualTo("true"); } diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index fa86667ef3..61b91553ce 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -76,7 +76,7 @@ 2.0.0 4.2.0 2.3.26-incubating - 2.4.5 + 5.4.0 3.0.0 2.4.11 2.8.0 @@ -1250,6 +1250,11 @@ httpcore ${httpcore.version} + + org.apache.httpcomponents + httpcore-nio + ${httpcore.version} + org.apache.httpcomponents httpmime