From fa84b179a8d8a53988c7a11a0f37a9d9ab33642d Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 18 Mar 2016 09:08:41 +0100 Subject: [PATCH] Allow to customize the Couchbase environment Closes gh-5403 --- .../couchbase/CouchbaseAutoConfiguration.java | 31 ++- .../couchbase/CouchbaseProperties.java | 179 +++++++++++++++++- .../CouchbaseAutoConfigurationTests.java | 54 +++++- .../appendix-application-properties.adoc | 10 + .../main/asciidoc/spring-boot-features.adoc | 14 ++ 5 files changed, 285 insertions(+), 3 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java index c99249bce4..38846c4a61 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -64,7 +64,7 @@ public class CouchbaseAutoConfiguration { @Bean @Primary public CouchbaseEnvironment couchbaseEnvironment() throws Exception { - return DefaultCouchbaseEnvironment.create(); + return createEnvironment(this.properties); } @Bean @@ -88,6 +88,35 @@ public class CouchbaseAutoConfiguration { this.properties.getBucket().getPassword()); } + /** + * Create a {@link CouchbaseEnvironment} based on the specified settings. + * @param properties the couchbase properties to use + * @return a {@link CouchbaseEnvironment} + */ + protected CouchbaseEnvironment createEnvironment(CouchbaseProperties properties) { + CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints(); + CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts(); + DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment.builder() + .connectTimeout(timeouts.getConnect()) + .kvEndpoints(endpoints.getKeyValue()) + .kvTimeout(timeouts.getKeyValue()) + .queryEndpoints(endpoints.getQuery()) + .queryTimeout(timeouts.getQuery()) + .viewEndpoints(endpoints.getView()) + .viewTimeout(timeouts.getView()); + CouchbaseProperties.Ssl ssl = properties.getEnv().getSsl(); + if (ssl.getEnabled()) { + builder.sslEnabled(true); + if (ssl.getKeyStore() != null) { + builder.sslKeystoreFile(ssl.getKeyStore()); + } + if (ssl.getKeyStorePassword() != null) { + builder.sslKeystorePassword(ssl.getKeyStorePassword()); + } + } + return builder.build(); + } + } /** diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java index a703f7b0a5..ad95aeebce 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java @@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.couchbase; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.util.StringUtils; /** * Configuration properties for Couchbase. @@ -37,6 +39,8 @@ public class CouchbaseProperties { private final Bucket bucket = new Bucket(); + private final Env env = new Env(); + public List getBootstrapHosts() { return this.bootstrapHosts; } @@ -49,7 +53,12 @@ public class CouchbaseProperties { return this.bucket; } - static class Bucket { + public Env getEnv() { + return this.env; + } + + + public static class Bucket { /** * Name of the bucket to connect to. @@ -79,4 +88,172 @@ public class CouchbaseProperties { } + public static class Env { + + @NestedConfigurationProperty + private final Endpoints endpoints = new Endpoints(); + + @NestedConfigurationProperty + private final Ssl ssl = new Ssl(); + + @NestedConfigurationProperty + private final Timeouts timeouts = new Timeouts(); + + public Endpoints getEndpoints() { + return this.endpoints; + } + + public Ssl getSsl() { + return this.ssl; + } + + public Timeouts getTimeouts() { + return this.timeouts; + } + + } + + public static class Endpoints { + + /** + * Number of sockets per node against the Key/value service. + */ + private int keyValue = 1; + + /** + * Number of sockets per node against the Query (N1QL) service. + */ + private int query = 1; + + /** + * Number of sockets per node against the view service. + */ + private int view = 1; + + public int getKeyValue() { + return this.keyValue; + } + + public void setKeyValue(int keyValue) { + this.keyValue = keyValue; + } + + public int getQuery() { + return this.query; + } + + public void setQuery(int query) { + this.query = query; + } + + public int getView() { + return this.view; + } + + public void setView(int view) { + this.view = view; + } + + } + + public static class Ssl { + + /** + * Enable SSL support. Enabled automatically if a "keyStore" is provided unless + * specified otherwise. + */ + private Boolean enabled; + + /** + * Path to the JVM key store that holds the certificates. + */ + private String keyStore; + + /** + * Password used to access the key store. + */ + private String keyStorePassword; + + public Boolean getEnabled() { + return (this.enabled != null ? this.enabled : StringUtils.hasText(this.keyStore)); + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getKeyStore() { + return this.keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return this.keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + } + + public static class Timeouts { + + /** + * Bucket connections timeout in milliseconds. + */ + private long connect = 5000; + + /** + * Blocking operations performed on a specific key timeout in milliseconds. + */ + private long keyValue = 2500; + + /** + * N1QL query operations timeout in milliseconds. + */ + private long query = 7500; + + /** + * Regular and geospatial view operations timeout in milliseconds. + */ + private long view = 7500; + + public long getConnect() { + return this.connect; + } + + public void setConnect(long connect) { + this.connect = connect; + } + + public long getKeyValue() { + return this.keyValue; + } + + public void setKeyValue(long keyValue) { + this.keyValue = keyValue; + } + + public long getQuery() { + return this.query; + } + + public void setQuery(long query) { + this.query = query; + } + + public long getView() { + return this.view; + } + + public void setView(long view) { + this.view = view; + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java index 24b20e7a0e..3677d98356 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java @@ -20,6 +20,7 @@ import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.cluster.ClusterInfo; import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -58,7 +59,6 @@ public class CouchbaseAutoConfigurationTests extends AbstractCouchbaseAutoConfig assertThat(this.context.getBeansOfType(CouchbaseTestConfigurer.class)) .hasSize(1); assertNoCouchbaseBeans(); - } private void assertNoCouchbaseBeans() { @@ -69,4 +69,56 @@ public class CouchbaseAutoConfigurationTests extends AbstractCouchbaseAutoConfig assertThat(this.context.getBeansOfType(Bucket.class)).isEmpty(); } + @Test + public void customizeEnvEndpoints() throws Exception { + DefaultCouchbaseEnvironment env = customizeEnv( + "spring.couchbase.env.endpoints.keyValue=4", + "spring.couchbase.env.endpoints.query=5", + "spring.couchbase.env.endpoints.view=6"); + assertThat(env.kvEndpoints()).isEqualTo(4); + assertThat(env.queryEndpoints()).isEqualTo(5); + assertThat(env.viewEndpoints()).isEqualTo(6); + } + + @Test + public void customizeEnvTimeouts() throws Exception { + DefaultCouchbaseEnvironment env = customizeEnv( + "spring.couchbase.env.timeouts.connect=100", + "spring.couchbase.env.timeouts.keyValue=200", + "spring.couchbase.env.timeouts.query=300", + "spring.couchbase.env.timeouts.view=400"); + assertThat(env.connectTimeout()).isEqualTo(100); + assertThat(env.kvTimeout()).isEqualTo(200); + assertThat(env.queryTimeout()).isEqualTo(300); + assertThat(env.viewTimeout()).isEqualTo(400); + } + + @Test + public void enableSslNoEnabledFlag() throws Exception { + DefaultCouchbaseEnvironment env = customizeEnv( + "spring.couchbase.env.ssl.keyStore=foo", + "spring.couchbase.env.ssl.keyStorePassword=secret"); + assertThat(env.sslEnabled()).isTrue(); + assertThat(env.sslKeystoreFile()).isEqualTo("foo"); + assertThat(env.sslKeystorePassword()).isEqualTo("secret"); + } + + @Test + public void disableSslEvenWithKeyStore() throws Exception { + DefaultCouchbaseEnvironment env = customizeEnv( + "spring.couchbase.env.ssl.enabled=false", + "spring.couchbase.env.ssl.keyStore=foo", + "spring.couchbase.env.ssl.keyStorePassword=secret"); + assertThat(env.sslEnabled()).isFalse(); + assertThat(env.sslKeystoreFile()).isNull(); + assertThat(env.sslKeystorePassword()).isNull(); + } + + private DefaultCouchbaseEnvironment customizeEnv(String... environment) throws Exception { + load(CouchbaseTestConfigurer.class, environment); + CouchbaseProperties properties = this.context.getBean(CouchbaseProperties.class); + return (DefaultCouchbaseEnvironment) new CouchbaseAutoConfiguration.CouchbaseConfiguration(properties) + .couchbaseEnvironment(); + } + } 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 8803eb0b9c..f58dd2c0b8 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -478,6 +478,16 @@ content into your application; rather pick only the properties that you need. spring.couchbase.bootstrap-hosts= # Couchbase nodes (host or IP address) to bootstrap from. spring.couchbase.bucket.name=default # Name of the bucket to connect to. spring.couchbase.bucket.password= # Password of the bucket. + spring.couchbase.env.endpoints.key-value=1 # Number of sockets per node against the Key/value service. + spring.couchbase.env.endpoints.query=1 # Number of sockets per node against the Query (N1QL) service. + spring.couchbase.env.endpoints.view=1 # Number of sockets per node against the view service. + spring.couchbase.env.ssl.enabled= # Enable SSL support. Enabled automatically if a "keyStore" is provided unless specified otherwise. + spring.couchbase.env.ssl.key-store= # Path to the JVM key store that holds the certificates. + spring.couchbase.env.ssl.key-store-password= # Password used to access the key store. + spring.couchbase.env.timeouts.connect=5000 # Bucket connections timeout in milliseconds. + spring.couchbase.env.timeouts.key-value=2500 # Blocking operations performed on a specific key timeout in milliseconds. + spring.couchbase.env.timeouts.query=7500 # N1QL query operations timeout in milliseconds. + spring.couchbase.env.timeouts.view=7500 # Regular and geospatial view operations timeout in milliseconds. # DAO ({sc-spring-boot-autoconfigure}/dao/PersistenceExceptionTranslationAutoConfiguration.{sc-ext}[PersistenceExceptionTranslationAutoConfiguration]) spring.dao.exceptiontranslation.enabled=true # Enable the PersistenceExceptionTranslationPostProcessor. 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 837fe23ddc..006ce7eb54 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3217,6 +3217,20 @@ own `org.springframework.data.couchbase.config.CouchbaseConfigurer` `@Bean` to t control over the whole configuration. ==== +It is also possible to customize some of the `CouchbaseEnvironment` settings. For instance +the following configuration changes the timeout to use to open a new `Bucket` and enable +SSL support: + +[source,properties,indent=0] +---- + spring.couchbase.env.timeouts.connect=3000 + spring.couchbase.env.ssl.key-store=/location/of/keystore.jks + spring.couchbase.env.ssl.key-store-password=secret +---- + +Check the `spring.couchbase.env.*` properties for more details. + + [[boot-features-spring-data-couchbase-repositories]] ==== Spring Data Couchbase repositories Spring Data includes repository support for Couchbase. For complete details of Spring