From e67f2e29830846fe464db0c41c1772e509aee2d9 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 7 Mar 2016 13:02:43 +0100 Subject: [PATCH] Separate Couchbase setup from Spring Data This commit separates the basic setup of Couchbase from Spring Data so that a `Bucket` and `Cluster` bucket beans are exposed even if Spring Data is not available. A basic setup happens if `spring.couchbase.bootstrap-hosts` is specified, configuring the `default` bucket with no authentication unless specified otherwise. If Spring Data is available, those beans are re-used by default to configure the `CouchbaseTemplate` and other repository-related beans. Closes gh-5347 --- .../couchbase/CouchbaseAutoConfiguration.java | 97 +++++------ .../couchbase/CouchbaseProperties.java | 37 +---- ...uchbaseConfigurerAdapterConfiguration.java | 52 ++++++ .../CouchbaseDataAutoConfiguration.java | 63 ++++++++ .../couchbase/CouchbaseDataProperties.java | 58 +++++++ .../CouchbaseRepositoriesRegistrar.java | 2 +- .../SpringBootCouchbaseConfigurer.java | 70 ++++++++ .../SpringBootCouchbaseDataConfiguration.java | 76 +++++++++ .../main/resources/META-INF/spring.factories | 1 + ...stractCouchbaseAutoConfigurationTests.java | 51 ++++++ ...baseAutoConfigurationIntegrationTests.java | 78 +++++++++ .../CouchbaseAutoConfigurationTests.java | 145 +++-------------- ...tion.java => CouchbaseTestConfigurer.java} | 23 ++- .../couchbase/CouchbaseTestServer.java | 120 ++++++++++++++ .../CouchbaseDataAutoConfigurationTests.java | 150 ++++++++++++++++++ ...aseRepositoriesAutoConfigurationTests.java | 9 +- spring-boot-dependencies/pom.xml | 8 +- .../appendix-application-properties.adoc | 10 +- .../main/asciidoc/spring-boot-features.adoc | 40 +++-- .../src/test/resources/application.properties | 3 +- 20 files changed, 835 insertions(+), 258 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseConfigurer.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/AbstractCouchbaseAutoConfigurationTests.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java rename spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/{CouchbaseTestConfiguration.java => CouchbaseTestConfigurer.java} (69%) create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestServer.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java 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 511d3773514..c99249bce46 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 @@ -16,11 +16,13 @@ package org.springframework.boot.autoconfigure.couchbase; -import java.util.List; - -import javax.validation.Validator; - +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; import com.couchbase.client.java.CouchbaseBucket; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; @@ -32,11 +34,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; -import org.springframework.data.couchbase.core.CouchbaseTemplate; -import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; -import org.springframework.data.couchbase.core.query.Consistency; -import org.springframework.data.couchbase.repository.support.IndexManager; +import org.springframework.context.annotation.Primary; +import org.springframework.data.couchbase.config.CouchbaseConfigurer; /** * {@link EnableAutoConfiguration Auto-Configuration} for Couchbase. @@ -46,27 +45,15 @@ import org.springframework.data.couchbase.repository.support.IndexManager; * @since 1.4.0 */ @Configuration -@ConditionalOnClass({ CouchbaseBucket.class, AbstractCouchbaseConfiguration.class }) +@ConditionalOnClass({CouchbaseBucket.class, Cluster.class}) @Conditional(CouchbaseAutoConfiguration.CouchbaseCondition.class) @EnableConfigurationProperties(CouchbaseProperties.class) public class CouchbaseAutoConfiguration { - @Configuration - @ConditionalOnClass(Validator.class) - public static class ValidationConfiguration { - - @Bean - @ConditionalOnBean(Validator.class) - public ValidatingCouchbaseEventListener validationEventListener( - Validator validator) { - return new ValidatingCouchbaseEventListener(validator); - } - - } @Configuration - @ConditionalOnMissingBean(AbstractCouchbaseConfiguration.class) - public static class CouchbaseConfiguration extends AbstractCouchbaseConfiguration { + @ConditionalOnMissingBean(CouchbaseConfigurer.class) + public static class CouchbaseConfiguration { private final CouchbaseProperties properties; @@ -74,51 +61,39 @@ public class CouchbaseAutoConfiguration { this.properties = properties; } - @Override - protected List getBootstrapHosts() { - return this.properties.getBootstrapHosts(); - } - - @Override - protected String getBucketName() { - return this.properties.getBucket().getName(); - } - - @Override - protected String getBucketPassword() { - return this.properties.getBucket().getPassword(); + @Bean + @Primary + public CouchbaseEnvironment couchbaseEnvironment() throws Exception { + return DefaultCouchbaseEnvironment.create(); } - @Override - protected Consistency getDefaultConsistency() { - return this.properties.getConsistency(); + @Bean + @Primary + public Cluster couchbaseCluster() throws Exception { + return CouchbaseCluster.create(couchbaseEnvironment(), + this.properties.getBootstrapHosts()); } - @Override - @ConditionalOnMissingBean(name = "couchbaseTemplate") - @Bean(name = "couchbaseTemplate") - public CouchbaseTemplate couchbaseTemplate() throws Exception { - return super.couchbaseTemplate(); + @Bean + @Primary + public ClusterInfo couchbaseClusterInfo() throws Exception { + return couchbaseCluster().clusterManager(this.properties.getBucket().getName(), + this.properties.getBucket().getPassword()).info(); } - @Override - @ConditionalOnMissingBean(name = "couchbaseIndexManager") - @Bean(name = "couchbaseIndexManager") - public IndexManager indexManager() { - if (this.properties.isAutoIndex()) { - return new IndexManager(true, true, true); - } - else { - return new IndexManager(false, false, false); - } + @Bean + @Primary + public Bucket couchbaseClient() throws Exception { + return couchbaseCluster().openBucket(this.properties.getBucket().getName(), + this.properties.getBucket().getPassword()); } } /** * Determine if Couchbase should be configured. This happens if either the - * user-configuration defines a couchbase configuration or if at least the bucket name - * is specified. + * user-configuration defines a {@link CouchbaseConfigurer} or if at least + * the "bootstrapHosts" property is specified. */ static class CouchbaseCondition extends AnyNestedCondition { @@ -126,12 +101,12 @@ public class CouchbaseAutoConfiguration { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnProperty(prefix = "spring.data.couchbase.bucket", name = "name") - static class BucketNameProperty { + @ConditionalOnProperty(prefix = "spring.couchbase", name = "bootstrapHosts") + static class BootstrapHostsProperty { } - @ConditionalOnBean(AbstractCouchbaseConfiguration.class) - static class CouchbaseConfiguration { + @ConditionalOnBean(CouchbaseConfigurer.class) + static class CouchbaseConfigurerAvailable { } } 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 9d8a98e79ba..a703f7b0a5b 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 @@ -16,12 +16,9 @@ package org.springframework.boot.autoconfigure.couchbase; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.data.couchbase.core.query.Consistency; /** * Configuration properties for Couchbase. @@ -30,36 +27,16 @@ import org.springframework.data.couchbase.core.query.Consistency; * @author Stephane Nicoll * @since 1.4.0 */ -@ConfigurationProperties(prefix = "spring.data.couchbase") +@ConfigurationProperties(prefix = "spring.couchbase") public class CouchbaseProperties { - /** - * Automatically create views and indexes. Use the meta-data provided by - * "@ViewIndexed", "@N1qlPrimaryIndexed" and "@N1qlSecondaryIndexed". - */ - private boolean autoIndex; - /** * Couchbase nodes (host or IP address) to bootstrap from. */ - private List bootstrapHosts = new ArrayList( - Collections.singletonList("localhost")); + private List bootstrapHosts; private final Bucket bucket = new Bucket(); - /** - * Consistency to apply by default on generated queries. - */ - private Consistency consistency = Consistency.READ_YOUR_OWN_WRITES; - - public boolean isAutoIndex() { - return this.autoIndex; - } - - public void setAutoIndex(boolean autoIndex) { - this.autoIndex = autoIndex; - } - public List getBootstrapHosts() { return this.bootstrapHosts; } @@ -72,20 +49,12 @@ public class CouchbaseProperties { return this.bucket; } - public Consistency getConsistency() { - return this.consistency; - } - - public void setConsistency(Consistency consistency) { - this.consistency = consistency; - } - static class Bucket { /** * Name of the bucket to connect to. */ - private String name; + private String name = "default"; /** * Password of the bucket. diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java new file mode 100644 index 00000000000..86d9e37db89 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseConfigurerAdapterConfiguration.java @@ -0,0 +1,52 @@ +/* + * 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.data.couchbase; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration.CouchbaseConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.CouchbaseConfigurer; + +/** + * Adapt the core Couchbase configuration to an expected {@link CouchbaseConfigurer} + * if necessary. + * + * @author Stephane Nicoll + */ +@Configuration +@ConditionalOnClass(CouchbaseConfigurer.class) +@ConditionalOnBean(CouchbaseConfiguration.class) +class CouchbaseConfigurerAdapterConfiguration { + + private final CouchbaseConfiguration configuration; + + CouchbaseConfigurerAdapterConfiguration(CouchbaseConfiguration configuration) { + this.configuration = configuration; + } + + @Bean + @ConditionalOnMissingBean + public CouchbaseConfigurer springBootCouchbaseConfigurer() throws Exception { + return new SpringBootCouchbaseConfigurer(this.configuration.couchbaseEnvironment(), + this.configuration.couchbaseCluster(), this.configuration.couchbaseClusterInfo(), + this.configuration.couchbaseClient()); + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java new file mode 100644 index 00000000000..537f676a347 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java @@ -0,0 +1,63 @@ +/* + * 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.data.couchbase; + +import javax.validation.Validator; + +import com.couchbase.client.java.Bucket; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.data.couchbase.repository.CouchbaseRepository; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase support. + * + * @author Eddú Meléndez + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@ConditionalOnClass({Bucket.class, CouchbaseRepository.class}) +@AutoConfigureAfter(CouchbaseAutoConfiguration.class) +@EnableConfigurationProperties(CouchbaseDataProperties.class) +@Import({ CouchbaseConfigurerAdapterConfiguration.class, + SpringBootCouchbaseDataConfiguration.class }) +public class CouchbaseDataAutoConfiguration { + + @Configuration + @ConditionalOnClass(Validator.class) + public static class ValidationConfiguration { + + @Bean + @ConditionalOnBean(Validator.class) + public ValidatingCouchbaseEventListener validationEventListener( + Validator validator) { + return new ValidatingCouchbaseEventListener(validator); + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java new file mode 100644 index 00000000000..020487084f9 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java @@ -0,0 +1,58 @@ +/* + * 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.data.couchbase; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.couchbase.core.query.Consistency; + +/** + * Configuration properties for Spring Data Couchbase. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.couchbase") +public class CouchbaseDataProperties { + + /** + * Automatically create views and indexes. Use the meta-data provided by + * "@ViewIndexed", "@N1qlPrimaryIndexed" and "@N1qlSecondaryIndexed". + */ + private boolean autoIndex; + + /** + * Consistency to apply by default on generated queries. + */ + private Consistency consistency = Consistency.READ_YOUR_OWN_WRITES; + + public boolean isAutoIndex() { + return this.autoIndex; + } + + public void setAutoIndex(boolean autoIndex) { + this.autoIndex = autoIndex; + } + + public Consistency getConsistency() { + return this.consistency; + } + + public void setConsistency(Consistency consistency) { + this.consistency = consistency; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java index 3fd17760b2f..855cdafe276 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java @@ -31,7 +31,7 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi * @author Eddú Meléndez * @since 1.4.0 */ -public class CouchbaseRepositoriesRegistrar +class CouchbaseRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { @Override diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseConfigurer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseConfigurer.java new file mode 100644 index 00000000000..66dc789ef4f --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseConfigurer.java @@ -0,0 +1,70 @@ +/* + * 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.data.couchbase; + +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 org.springframework.data.couchbase.config.CouchbaseConfigurer; + +/** + * A simple {@link CouchbaseConfigurer} implementation. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class SpringBootCouchbaseConfigurer implements CouchbaseConfigurer { + + private final CouchbaseEnvironment env; + + private final Cluster cluster; + + private final ClusterInfo clusterInfo; + + private final Bucket bucket; + + public SpringBootCouchbaseConfigurer(CouchbaseEnvironment env, Cluster cluster, + ClusterInfo clusterInfo, Bucket bucket) { + this.env = env; + this.cluster = cluster; + this.clusterInfo = clusterInfo; + this.bucket = bucket; + } + + @Override + public CouchbaseEnvironment couchbaseEnvironment() throws Exception { + return this.env; + } + + @Override + public Cluster couchbaseCluster() throws Exception { + return this.cluster; + } + + @Override + public ClusterInfo couchbaseClusterInfo() throws Exception { + return this.clusterInfo; + } + + @Override + public Bucket couchbaseClient() throws Exception { + return this.bucket; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java new file mode 100644 index 00000000000..d0ae4065fc9 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java @@ -0,0 +1,76 @@ +/* + * 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.data.couchbase; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.config.CouchbaseConfigurer; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.data.couchbase.core.query.Consistency; +import org.springframework.data.couchbase.repository.support.IndexManager; + +/** + * Configure Spring Data's couchbase support. + * + * @author Stephane Nicoll + */ +@Configuration +@ConditionalOnMissingBean(AbstractCouchbaseDataConfiguration.class) +@ConditionalOnBean(CouchbaseConfigurer.class) +class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfiguration { + + @Autowired + private CouchbaseDataProperties properties; + + @Autowired(required = false) + private CouchbaseConfigurer couchbaseConfigurer; + + @Override + protected CouchbaseConfigurer couchbaseConfigurer() { + return this.couchbaseConfigurer; + } + + @Override + protected Consistency getDefaultConsistency() { + return this.properties.getConsistency(); + } + + @Override + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE) + @Bean(name = BeanNames.COUCHBASE_TEMPLATE) + public CouchbaseTemplate couchbaseTemplate() throws Exception { + return super.couchbaseTemplate(); + } + + @Override + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_INDEX_MANAGER) + @Bean(name = BeanNames.COUCHBASE_INDEX_MANAGER) + public IndexManager indexManager() { + if (this.properties.isAutoIndex()) { + return new IndexManager(true, true, true); + } + else { + return new IndexManager(false, false, false); + } + } + +} 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 d77f025aa65..5426fe47a96 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -23,6 +23,7 @@ org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\ org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/AbstractCouchbaseAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/AbstractCouchbaseAutoConfigurationTests.java new file mode 100644 index 00000000000..68be602657d --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/AbstractCouchbaseAutoConfigurationTests.java @@ -0,0 +1,51 @@ +/* + * 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.couchbase; + +import org.junit.After; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * @author Stephane Nicoll + */ +public abstract class AbstractCouchbaseAutoConfigurationTests { + + protected AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + protected void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(context, environment); + if (config != null) { + context.register(config); + } + context.register(PropertyPlaceholderAutoConfiguration.class, + CouchbaseAutoConfiguration.class); + context.refresh(); + this.context = context; + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java new file mode 100644 index 00000000000..34e7da3ca22 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java @@ -0,0 +1,78 @@ +/* + * 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.couchbase; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseBucket; +import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.junit.Rule; +import org.junit.Test; + +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; + +/** + * Integration tests for {@link CouchbaseAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class CouchbaseAutoConfigurationIntegrationTests + extends AbstractCouchbaseAutoConfigurationTests { + + @Rule + public final CouchbaseTestServer couchbase = new CouchbaseTestServer(); + + @Test + public void defaultConfiguration() { + load(null, "spring.couchbase.bootstrapHosts=localhost"); + assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(1); + assertThat(this.context.getBeansOfType(ClusterInfo.class)).hasSize(1); + assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); + assertThat(this.context.getBeansOfType(Bucket.class)).hasSize(1); + } + + @Test + public void customConfiguration() { + load(CustomConfiguration.class, "spring.couchbase.bootstrapHosts=localhost"); + assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(2); + assertThat(this.context.getBeansOfType(ClusterInfo.class)).hasSize(1); + assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); + assertThat(this.context.getBeansOfType(Bucket.class)).hasSize(2); + } + + + @Configuration + static class CustomConfiguration { + + @Bean + public Cluster myCustomCouchbaseCluster() throws Exception { + return mock(Cluster.class); + } + + @Bean + public Bucket myCustomCouchbaseClient() { + return mock(CouchbaseBucket.class); + } + + } + +} 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 9d97ade7286..24b20e7a0e3 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 @@ -16,29 +16,15 @@ package org.springframework.boot.autoconfigure.couchbase; -import javax.validation.Validator; - import com.couchbase.client.java.Bucket; -import org.junit.After; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.env.CouchbaseEnvironment; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.beans.DirectFieldAccessor; -import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.EnvironmentTestUtils; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; -import org.springframework.data.couchbase.core.CouchbaseTemplate; -import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; -import org.springframework.data.couchbase.core.query.Consistency; -import org.springframework.data.couchbase.repository.support.IndexManager; - import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; /** * Tests for {@link CouchbaseAutoConfiguration} @@ -46,128 +32,41 @@ import static org.mockito.Mockito.mock; * @author Eddú Meléndez * @author Stephane Nicoll */ -public class CouchbaseAutoConfigurationTests { +public class CouchbaseAutoConfigurationTests extends AbstractCouchbaseAutoConfigurationTests { @Rule public ExpectedException thrown = ExpectedException.none(); - private AnnotationConfigApplicationContext context; - - @After - public void close() { - if (this.context != null) { - this.context.close(); - } - } - @Test - public void bucketNameIsRequired() { + public void bootstrapHostsIsRequired() { load(null); - assertThat(this.context.getBeansOfType(CouchbaseTemplate.class)).isEmpty(); - assertThat(this.context.getBeansOfType(Bucket.class)).isEmpty(); - assertThat(this.context.getBeansOfType(ValidatingCouchbaseEventListener.class)) - .isEmpty(); + assertNoCouchbaseBeans(); } @Test - public void bucketNameIsNotRequiredIfCustomConfigurationIsSpecified() - throws Exception { - load(CouchbaseTestConfiguration.class); - assertThat(this.context.getBeansOfType(AbstractCouchbaseConfiguration.class)) + public void bootstrapHostsNotRequiredIfCouchbaseConfigurerIsSet() { + load(CouchbaseTestConfigurer.class); + assertThat(this.context.getBeansOfType(CouchbaseTestConfigurer.class)) .hasSize(1); - CouchbaseTestConfiguration configuration = this.context - .getBean(CouchbaseTestConfiguration.class); - assertThat(this.context.getBean(CouchbaseTemplate.class)) - .isSameAs(configuration.couchbaseTemplate()); - assertThat(this.context.getBean(Bucket.class)) - .isSameAs(configuration.couchbaseClient()); - assertThat(this.context.getBeansOfType(ValidatingCouchbaseEventListener.class)) - .isEmpty(); - } - - @Test - public void validatorIsPresent() { - load(ValidatorConfiguration.class); - - ValidatingCouchbaseEventListener listener = this.context - .getBean(ValidatingCouchbaseEventListener.class); - assertThat(new DirectFieldAccessor(listener).getPropertyValue("validator")) - .isEqualTo(this.context.getBean(Validator.class)); - } - - @Test - public void autoIndexIsDisabledByDefault() { - load(CouchbaseTestConfiguration.class); - CouchbaseTestConfiguration configuration = this.context - .getBean(CouchbaseTestConfiguration.class); - IndexManager indexManager = configuration.indexManager(); - assertThat(indexManager.isIgnoreViews()).isTrue(); - assertThat(indexManager.isIgnoreN1qlPrimary()).isTrue(); - assertThat(indexManager.isIgnoreN1qlSecondary()).isTrue(); - } - - @Test - public void enableAutoIndex() { - load(CouchbaseTestConfiguration.class, "spring.data.couchbase.auto-index=true"); - CouchbaseTestConfiguration configuration = this.context - .getBean(CouchbaseTestConfiguration.class); - IndexManager indexManager = configuration.indexManager(); - assertThat(indexManager.isIgnoreViews()).isFalse(); - assertThat(indexManager.isIgnoreN1qlPrimary()).isFalse(); - assertThat(indexManager.isIgnoreN1qlSecondary()).isFalse(); + // No beans are going to be created + assertNoCouchbaseBeans(); } @Test - public void changeConsistency() { - load(CouchbaseTestConfiguration.class, - "spring.data.couchbase.consistency=eventually-consistent"); - CouchbaseTestConfiguration configuration = this.context - .getBean(CouchbaseTestConfiguration.class); - assertThat(configuration.getDefaultConsistency()) - .isEqualTo(Consistency.EVENTUALLY_CONSISTENT); - } - - @Test - public void overrideCouchbaseOperations() { - load(CouchbaseTemplateConfiguration.class); - CouchbaseTemplateConfiguration configuration = this.context - .getBean(CouchbaseTemplateConfiguration.class); - assertThat(this.context.getBean(CouchbaseTemplate.class)) - .isSameAs(configuration.myCouchbaseTemplate()); - } - - private void load(Class config, String... environment) { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(context, environment); - if (config != null) { - context.register(config); - } - context.register(PropertyPlaceholderAutoConfiguration.class, - CouchbaseAutoConfiguration.class); - context.refresh(); - this.context = context; - } - - @Configuration - @Import(CouchbaseTestConfiguration.class) - static class ValidatorConfiguration { - - @Bean - public Validator myValidator() { - return mock(Validator.class); - } + public void bootstrapHostsIgnoredIfCouchbaseConfigurerIsSet() { + load(CouchbaseTestConfigurer.class, "spring.couchbase.bootstrapHosts=localhost"); + assertThat(this.context.getBeansOfType(CouchbaseTestConfigurer.class)) + .hasSize(1); + assertNoCouchbaseBeans(); } - @Configuration - @Import(CouchbaseTestConfiguration.class) - static class CouchbaseTemplateConfiguration { - - @Bean(name = "couchbaseTemplate") - public CouchbaseTemplate myCouchbaseTemplate() { - return mock(CouchbaseTemplate.class); - } - + private void assertNoCouchbaseBeans() { + // No beans are going to be created + assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).isEmpty(); + assertThat(this.context.getBeansOfType(ClusterInfo.class)).isEmpty(); + assertThat(this.context.getBeansOfType(Cluster.class)).isEmpty(); + assertThat(this.context.getBeansOfType(Bucket.class)).isEmpty(); } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfiguration.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfigurer.java similarity index 69% rename from spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfiguration.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfigurer.java index 7291c9f8b57..e0243311b7c 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfiguration.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfigurer.java @@ -19,40 +19,39 @@ package org.springframework.boot.autoconfigure.couchbase; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.CouchbaseBucket; -import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.env.CouchbaseEnvironment; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.CouchbaseConfigurer; +import org.springframework.stereotype.Component; import static org.mockito.Mockito.mock; /** - * Test configuration for couchbase that mocks access. + * Test configurer for couchbase that mocks access. * * @author Stephane Nicoll */ -@Configuration -public class CouchbaseTestConfiguration - extends CouchbaseAutoConfiguration.CouchbaseConfiguration { +@Component +public class CouchbaseTestConfigurer implements CouchbaseConfigurer { - public CouchbaseTestConfiguration(CouchbaseProperties properties) { - super(properties); + @Override + public CouchbaseEnvironment couchbaseEnvironment() throws Exception { + return mock(CouchbaseEnvironment.class); } @Override public Cluster couchbaseCluster() throws Exception { - return mock(CouchbaseCluster.class); + return mock(Cluster.class); } @Override - @Bean public ClusterInfo couchbaseClusterInfo() { return mock(ClusterInfo.class); } @Override - public Bucket couchbaseClient() throws Exception { + public Bucket couchbaseClient() { return mock(CouchbaseBucket.class); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestServer.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestServer.java new file mode 100644 index 00000000000..d078ec1b53b --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestServer.java @@ -0,0 +1,120 @@ +/* + * 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.couchbase; + +import java.util.concurrent.TimeUnit; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assume; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * {@link TestRule} for working with an optional Couchbase server. Expects + * a default {@link Bucket} with no password to be available on localhost. + * + * @author Stephane Nicoll + */ +public class CouchbaseTestServer implements TestRule { + + private static final Log logger = LogFactory.getLog(CouchbaseTestServer.class); + + private CouchbaseEnvironment env; + + private Cluster cluster; + + @Override + public Statement apply(Statement base, Description description) { + try { + this.env = DefaultCouchbaseEnvironment.create(); + this.cluster = CouchbaseCluster.create(this.env, "localhost"); + testConnection(this.cluster); + return new CouchbaseStatement(base, this.env, this.cluster); + } + catch (Exception e) { + logger.info("No couchbase server available"); + return new SkipStatement(); + } + } + + private static void testConnection(Cluster cluster) { + Bucket bucket = cluster.openBucket(2, TimeUnit.SECONDS); + bucket.close(); + } + + /** + * @return the couchbase env if any + */ + public CouchbaseEnvironment getEnv() { + return this.env; + } + + /** + * @return the cluster if any + */ + public Cluster getCluster() { + return this.cluster; + } + + + private static class CouchbaseStatement extends Statement { + private final Statement base; + private final CouchbaseEnvironment env; + + private final Cluster cluster; + + CouchbaseStatement(Statement base, CouchbaseEnvironment env, Cluster cluster) { + this.base = base; + this.env = env; + this.cluster = cluster; + } + + @Override + public void evaluate() throws Throwable { + try { + this.base.evaluate(); + } + finally { + try { + this.cluster.disconnect(); + this.env.shutdownAsync(); + } + catch (Exception ex) { + logger.warn("Exception while trying to cleanup couchbase resource", ex); + } + } + } + } + + private static class SkipStatement extends Statement { + + @Override + public void evaluate() throws Throwable { + Assume.assumeTrue("Skipping test due to Couchbase " + + "not being available", false); + } + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java new file mode 100644 index 00000000000..345d2614a57 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java @@ -0,0 +1,150 @@ +/* + * 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.data.couchbase; + +import javax.validation.Validator; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfigurer; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; +import org.springframework.data.couchbase.config.CouchbaseConfigurer; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.data.couchbase.core.query.Consistency; +import org.springframework.data.couchbase.repository.support.IndexManager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CouchbaseDataAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class CouchbaseDataAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void disabledIfCouchbaseIsNotConfigured() { + load(null); + assertThat(this.context.getBeansOfType(IndexManager.class)).isEmpty(); + } + + @Test + public void customConfiguration() { + load(CustomCouchbaseConfiguration.class); + CouchbaseTemplate couchbaseTemplate = this.context.getBean(CouchbaseTemplate.class); + assertThat(couchbaseTemplate.getDefaultConsistency()).isEqualTo(Consistency.STRONGLY_CONSISTENT); + } + + @Test + public void validatorIsPresent() { + load(ValidatorConfiguration.class); + + ValidatingCouchbaseEventListener listener = this.context + .getBean(ValidatingCouchbaseEventListener.class); + assertThat(new DirectFieldAccessor(listener).getPropertyValue("validator")) + .isEqualTo(this.context.getBean(Validator.class)); + } + + @Test + public void autoIndexIsDisabledByDefault() { + load(CouchbaseTestConfigurer.class); + IndexManager indexManager = this.context.getBean(IndexManager.class); + assertThat(indexManager.isIgnoreViews()).isTrue(); + assertThat(indexManager.isIgnoreN1qlPrimary()).isTrue(); + assertThat(indexManager.isIgnoreN1qlSecondary()).isTrue(); + } + + @Test + public void enableAutoIndex() { + load(CouchbaseTestConfigurer.class, + "spring.data.couchbase.auto-index=true"); + IndexManager indexManager = this.context.getBean(IndexManager.class); + assertThat(indexManager.isIgnoreViews()).isFalse(); + assertThat(indexManager.isIgnoreN1qlPrimary()).isFalse(); + assertThat(indexManager.isIgnoreN1qlSecondary()).isFalse(); + } + + @Test + public void changeConsistency() { + load(CouchbaseTestConfigurer.class, + "spring.data.couchbase.consistency=eventually-consistent"); + SpringBootCouchbaseDataConfiguration configuration = this.context + .getBean(SpringBootCouchbaseDataConfiguration.class); + assertThat(configuration.getDefaultConsistency()) + .isEqualTo(Consistency.EVENTUALLY_CONSISTENT); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(context, environment); + if (config != null) { + context.register(config); + } + context.register(PropertyPlaceholderAutoConfiguration.class, + CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class); + context.refresh(); + this.context = context; + } + + + @Configuration + @Import(CouchbaseTestConfigurer.class) + static class ValidatorConfiguration { + + @Bean + public Validator myValidator() { + return mock(Validator.class); + } + + } + + @Configuration + static class CustomCouchbaseConfiguration extends AbstractCouchbaseDataConfiguration { + + @Override + protected CouchbaseConfigurer couchbaseConfigurer() { + return new CouchbaseTestConfigurer(); + } + + @Override + protected Consistency getDefaultConsistency() { + return Consistency.STRONGLY_CONSISTENT; + } + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java index ba564f520a5..9f633221409 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java @@ -22,7 +22,7 @@ import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; -import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfigurer; import org.springframework.boot.autoconfigure.data.couchbase.city.City; import org.springframework.boot.autoconfigure.data.couchbase.city.CityRepository; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; @@ -52,7 +52,7 @@ public class CouchbaseRepositoriesAutoConfigurationTests { @Test public void couchbaseNotAvailable() throws Exception { - load(CouchbaseNotAvailableConfiguration.class); + load(null); assertThat(this.context.getBeansOfType(CityRepository.class)).hasSize(0); } @@ -83,6 +83,7 @@ public class CouchbaseRepositoriesAutoConfigurationTests { } context.register(PropertyPlaceholderAutoConfiguration.class, CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class, CouchbaseRepositoriesAutoConfiguration.class); context.refresh(); this.context = context; @@ -96,14 +97,14 @@ public class CouchbaseRepositoriesAutoConfigurationTests { @Configuration @TestAutoConfigurationPackage(City.class) - @Import(CouchbaseTestConfiguration.class) + @Import(CouchbaseTestConfigurer.class) static class DefaultConfiguration { } @Configuration @TestAutoConfigurationPackage(EmptyDataPackage.class) - @Import(CouchbaseTestConfiguration.class) + @Import(CouchbaseTestConfigurer.class) protected static class NoRepositoryConfiguration { } diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index c9b099f12fc..aaa30b4990c 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -60,6 +60,7 @@ 2.1 1.6 2.4.2 + 2.2.3 1.3.2 10.12.1.1 3.1.2 @@ -133,7 +134,7 @@ 1.6.0.M1 1.2.1.RELEASE 3.0.6.RELEASE - Hopper-M1 + Hopper-BUILD-SNAPSHOT 0.19.0.RELEASE 4.3.0.M1 1.2.5.RELEASE @@ -519,6 +520,11 @@ transactions-jta ${atomikos.version} + + com.couchbase.client + java-client + ${couchbase-client.version} + com.datastax.cassandra cassandra-driver-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 f24c98749e7..d72b111985a 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -473,6 +473,11 @@ content into your application; rather pick only the properties that you need. liquibase.url= # JDBC url of the database to migrate. If not set, the primary configured data source is used. liquibase.user= # Login user of the database to migrate. + # COUCHBASE ({sc-spring-boot-autoconfigure}/couchbase/CouchbaseProperties.{sc-ext}[CouchbaseProperties]) + 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. + # DAO ({sc-spring-boot-autoconfigure}/dao/PersistenceExceptionTranslationAutoConfiguration.{sc-ext}[PersistenceExceptionTranslationAutoConfiguration]) spring.dao.exceptiontranslation.enabled=true # Enable the PersistenceExceptionTranslationPostProcessor. @@ -494,11 +499,8 @@ content into your application; rather pick only the properties that you need. spring.data.cassandra.ssl=false # Enable SSL support. spring.data.cassandra.username= # Login user of the server. - # COUCHBASE ({sc-spring-boot-autoconfigure}/couchbase/CouchbaseProperties.{sc-ext}[CouchbaseProperties]) + # DATA COUCHBASE ({sc-spring-boot-autoconfigure}/data/couchbase/CouchbaseDataProperties.{sc-ext}[CouchbaseDataProperties]) spring.data.couchbase.auto-index=false # Automatically create views and indexes. - spring.data.couchbase.bootstrap-hosts=localhost # Couchbase nodes (host or IP address) to bootstrap from. - spring.data.couchbase.bucket.name= # Name of the bucket to connect to. - spring.data.couchbase.bucket.password= # Password of the bucket. spring.data.couchbase.consistency=read-your-own-writes # Consistency to apply by default on generated queries. spring.data.couchbase.repositories.enabled=true # Enable Couchbase repositories. 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 c8e2aa66c70..9a1f6c41427 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3198,25 +3198,39 @@ dependencies in a convenient way. [[boot-features-connecting-to-couchbase]] ==== Connecting to Couchbase -You can inject an auto-configured `CouchbaseTemplate` instance as you would with any -other Spring Bean. The `spring.data.couchbase.*` properties can be used to customize the +You can very easily get a a `Bucket` and `Cluster` by adding the couchbase SDK and some +configuration. The `spring.couchbase.*` properties can be used to customize the connection. Generally you will provide the bootstrap hosts, bucket name and password: [source,properties,indent=0] ---- - spring.data.couchbase.bootstrap-hosts=my-host-1,192.168.1.123 - spring.data.couchbase.bucket.name=my-bucket - spring.data.couchbase.bucket.password=secret + spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123 + spring.couchbase.bucket.name=my-bucket + spring.couchbase.bucket.password=secret ---- [TIP] ==== -You need to provide _at least_ the bucket name, in which case the bootstrap host is -localhost and the password is an empty String. Alternatively, you can define your -own `org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration` `@Bean` -configuration to take control over the whole configuration. +You need to provide _at least_ the bootstrap host(s), in which case the bucket name +is `default` and the password is the empty String. Alternatively, you can define your +own `org.springframework.data.couchbase.config.CouchbaseConfigurer` `@Bean` to take +control over the whole configuration. ==== +[[boot-features-spring-data-couchbase-repositories]] +==== Spring Data Couchbase repositories +Spring Data includes repository support for Couchbase. For complete details of Spring +Data Couchbase, refer to their +http://docs.spring.io/spring-data/couchbase/docs/current/reference/html/[reference documentation]. + +You can inject an auto-configured `CouchbaseTemplate` instance as you would with any +other Spring Bean as long as a _default_ `CouchbaseConfigurer` is available (that +happens when you enable the couchbase support as explained above). If you want to +bypass the auto-configuration for Spring Data Couchbase, provide your own +`org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration` +implementation. + + [source,java,indent=0] ---- @Component @@ -3238,14 +3252,6 @@ If you add a `@Bean` of your own of type `CouchbaseTemplate` named `couchbaseTem will replace the default. - -[[boot-features-spring-data-couchbase-repositories]] -==== Spring Data Couchbase repositories -Spring Data includes repository support for Couchbase. For complete details of Spring -Data Couchbase, refer to their -http://docs.spring.io/spring-data/couchbase/docs/current/reference/html/[reference documentation]. - - [[boot-features-caching]] == Caching The Spring Framework provides support for transparently adding caching to an application. diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties index ef61d931440..ecc5de68fc8 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties @@ -1,2 +1,3 @@ +spring.couchbase.bootstrap-hosts=localhost + spring.data.couchbase.auto-index=true -spring.data.couchbase.bucket.name=default \ No newline at end of file