From 64a5cad09a7a37514d4290bf567539a7e1d7c80b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 16 Feb 2016 11:34:19 +0100 Subject: [PATCH] Improve couchbase support Expose an `auto-index` property that controls if views and indexes should be created automatically. Update the sample so that it uses this new property, lowering the manual steps to make it working on a vanilla couchbase server. See gh-3498 --- .../couchbase/CouchbaseAutoConfiguration.java | 25 +++++++++++- .../couchbase/CouchbaseProperties.java | 14 +++++++ .../CouchbaseAutoConfigurationTests.java | 40 +++++++++++++++++++ .../couchbase/CouchbaseTestConfiguration.java | 21 +--------- ...aseRepositoriesAutoConfigurationTests.java | 3 ++ .../appendix-application-properties.adoc | 1 + .../README.adoc | 17 +++++--- .../couchbase/SampleCouchbaseApplication.java | 9 +++-- .../sample/data/couchbase/UserRepository.java | 2 + .../src/test/resources/application.properties | 4 +- 10 files changed, 102 insertions(+), 34 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 df6e889f1c..12f14bd17a 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 @@ -33,8 +33,9 @@ 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.config.CouchbaseBucketFactoryBean; +import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.data.couchbase.repository.support.IndexManager; /** * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration @@ -45,7 +46,7 @@ import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbase * @since 1.4.0 */ @Configuration -@ConditionalOnClass({CouchbaseBucket.class, CouchbaseBucketFactoryBean.class}) +@ConditionalOnClass({CouchbaseBucket.class, AbstractCouchbaseConfiguration.class}) @Conditional(CouchbaseAutoConfiguration.CouchbaseCondition.class) @EnableConfigurationProperties(CouchbaseProperties.class) public class CouchbaseAutoConfiguration { @@ -77,6 +78,26 @@ public class CouchbaseAutoConfiguration { protected String getBucketPassword() { return this.properties.getBucket().getPassword(); } + + @Override + @ConditionalOnMissingBean(name = "couchbaseTemplate") + @Bean(name = "couchbaseTemplate") + public CouchbaseTemplate couchbaseTemplate() throws Exception { + return super.couchbaseTemplate(); + } + + @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); + } + } + } /** 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 a7b6f75507..82d3f6b0f4 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 @@ -32,6 +32,12 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "spring.data.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. */ @@ -39,6 +45,14 @@ public class CouchbaseProperties { private final Bucket bucket = new Bucket(); + public boolean isAutoIndex() { + return this.autoIndex; + } + + public void setAutoIndex(boolean autoIndex) { + this.autoIndex = autoIndex; + } + public List getBootstrapHosts() { return this.bootstrapHosts; } 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 35e23b434c..5694beab87 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 @@ -34,6 +34,7 @@ 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.repository.support.IndexManager; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -86,6 +87,33 @@ public class CouchbaseAutoConfigurationTests { .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(); + } + + @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); @@ -109,4 +137,16 @@ public class CouchbaseAutoConfigurationTests { } + + @Configuration + @Import(CouchbaseTestConfiguration.class) + static class CouchbaseTemplateConfiguration { + + @Bean(name = "couchbaseTemplate") + public CouchbaseTemplate myCouchbaseTemplate() { + return mock(CouchbaseTemplate.class); + } + + } + } 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/CouchbaseTestConfiguration.java index 2d93858431..1815ee9715 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/CouchbaseTestConfiguration.java @@ -16,9 +16,6 @@ package org.springframework.boot.autoconfigure.couchbase; -import java.util.Collections; -import java.util.List; - import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.CouchbaseBucket; @@ -27,7 +24,6 @@ import com.couchbase.client.java.cluster.ClusterInfo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import static org.mockito.Mockito.mock; @@ -37,22 +33,7 @@ import static org.mockito.Mockito.mock; * @author Stephane Nicoll */ @Configuration -public class CouchbaseTestConfiguration extends AbstractCouchbaseConfiguration { - - @Override - protected List getBootstrapHosts() { - return Collections.singletonList("localhost"); - } - - @Override - protected String getBucketName() { - return "my-bucket"; - } - - @Override - protected String getBucketPassword() { - return "my-password"; - } +public class CouchbaseTestConfiguration extends CouchbaseAutoConfiguration.CouchbaseConfiguration { @Override public Cluster couchbaseCluster() throws Exception { 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 8ab1d4e4a0..a8d2b20cc4 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,10 +22,12 @@ import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties; import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration; 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; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -65,6 +67,7 @@ public class CouchbaseRepositoriesAutoConfigurationTests { @Configuration @TestAutoConfigurationPackage(City.class) + @EnableConfigurationProperties(CouchbaseProperties.class) @Import({ CouchbaseRepositoriesRegistrar.class, CouchbaseTestConfiguration.class }) static class TestConfiguration { 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 49ddc57878..9af6e21a3b 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -489,6 +489,7 @@ content into your application; rather pick only the properties that you need. spring.data.cassandra.username= # Login user of the server. # COUCHBASE ({sc-spring-boot-autoconfigure}/couchbase/CouchbaseProperties.{sc-ext}[CouchbaseProperties]) + 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. diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc b/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc index 1a0058bd9c..926b7b2d95 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc @@ -2,13 +2,18 @@ This sample demonstrates how you can store a simple document using Spring Data Couchbase. -The sample expects couchbase to run on your machine with a bucket named `mybucket` and -`couchbase` for the password. You can customize these settings in `application.properties`. +The sample expects couchbase to run on your machine with a bucket named `default` and +no password. You can customize these settings in `application.properties`. -Before you use the sample, you need _at least_ to create an `all` view for the `User`: go -to the Couchbase server’s admin console and visit the Views screen, then click `Create -Development View` and name it `all` with `user` as document name. On that view, you need -to change the code to: +This sample also configures the `auto-index` property and the `UserRepository` defines +the `all` view so you should be able to invoke `findAll` for this sample. + +== Creating the view manually + +If you don't want to rely on `auto-index` and better understand how this works behind the +scenes, you need to create an `all` view for the `User`. Go to the Couchbase server’s +admin console and visit the Views screen, then click `Create Development View` and name +it `all` with `user` as document name. On that view, you need to change the code to: ```java function (doc, meta) { diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java index 4ba3ab4549..08743c2acd 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java @@ -35,18 +35,19 @@ public class SampleCouchbaseApplication implements CommandLineRunner { @Override public void run(String... args) throws Exception { - saveUsers(); + this.userRepository.deleteAll(); + User user = saveUser(); - System.out.println(this.userRepository.findAll()); + System.out.println(this.userRepository.findOne(user.getId())); } - private void saveUsers() { + private User saveUser() { User user = new User(); user.setId(UUID.randomUUID().toString()); user.setFirstName("Alice"); user.setLastName("Smith"); - this.userRepository.save(user); + return this.userRepository.save(user); } } diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java index 1e2deab5bc..bd13387c20 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java @@ -16,8 +16,10 @@ package sample.data.couchbase; +import org.springframework.data.couchbase.core.query.ViewIndexed; import org.springframework.data.couchbase.repository.CouchbaseRepository; +@ViewIndexed(designDoc = "user", viewName = "all") public interface UserRepository extends CouchbaseRepository { } 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 774aeb9a18..ef61d93144 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,2 @@ -spring.data.couchbase.bucket.name=mybucket -spring.data.couchbase.bucket.password=couchbase \ No newline at end of file +spring.data.couchbase.auto-index=true +spring.data.couchbase.bucket.name=default \ No newline at end of file