From 76f1ca4188c192d5cbf65ef441ae0685a5088092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 30 Jul 2015 02:49:50 -0500 Subject: [PATCH 1/2] Add Couchbase support Closes gh-3498 --- spring-boot-actuator/pom.xml | 5 + .../HealthIndicatorAutoConfiguration.java | 25 ++- .../health/CouchbaseHealthIndicator.java | 47 ++++++ ...HealthIndicatorAutoConfigurationTests.java | 27 +++ spring-boot-autoconfigure/pom.xml | 11 ++ .../couchbase/CouchbaseAutoConfiguration.java | 77 +++++++++ .../couchbase/CouchbaseProperties.java | 69 ++++++++ .../autoconfigure/couchbase/package-info.java | 20 +++ ...ouchbaseRepositoriesAutoConfiguration.java | 44 +++++ .../CouchbaseRepositoriesRegistrar.java | 56 +++++++ .../data/couchbase/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 2 + .../CouchbaseAutoConfigurationTests.java | 62 +++++++ .../couchbase/CityCouchbaseRepository.java | 26 +++ ...aseRepositoriesAutoConfigurationTests.java | 157 ++++++++++++++++++ .../data/couchbase/city/City.java | 33 ++++ .../data/couchbase/city/CityRepository.java | 23 +++ spring-boot-dependencies/pom.xml | 18 +- .../appendix-application-properties.adoc | 5 + spring-boot-samples/README.adoc | 2 + spring-boot-samples/pom.xml | 1 + .../spring-boot-sample-data-couchbase/pom.xml | 54 ++++++ .../couchbase/SampleCouchbaseApplication.java | 49 ++++++ .../main/java/sample/data/couchbase/User.java | 68 ++++++++ .../sample/data/couchbase/UserRepository.java | 23 +++ .../SampleCouchbaseApplicationTests.java | 47 ++++++ .../src/test/resources/application.properties | 3 + spring-boot-starters/pom.xml | 1 + .../pom.xml | 32 ++++ .../main/resources/META-INF/spring.provides | 1 + 30 files changed, 1006 insertions(+), 2 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/package-info.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties create mode 100644 spring-boot-starters/spring-boot-starter-data-couchbase/pom.xml create mode 100644 spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml index 2f387986cec..b3020634f69 100644 --- a/spring-boot-actuator/pom.xml +++ b/spring-boot-actuator/pom.xml @@ -151,6 +151,11 @@ spring-data-cassandra true + + org.springframework.data + spring-data-couchbase + true + org.springframework.data spring-data-mongodb diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java index 5b638a515cb..6d9a482f58c 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java @@ -22,6 +22,7 @@ import java.util.Map; import javax.jms.ConnectionFactory; import javax.sql.DataSource; +import com.couchbase.client.java.Bucket; import com.datastax.driver.core.Cluster; import org.apache.solr.client.solrj.SolrClient; import org.elasticsearch.client.Client; @@ -32,6 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.actuate.health.CassandraHealthIndicator; import org.springframework.boot.actuate.health.CompositeHealthIndicator; +import org.springframework.boot.actuate.health.CouchbaseHealthIndicator; import org.springframework.boot.actuate.health.DataSourceHealthIndicator; import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator; import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties; @@ -54,6 +56,7 @@ import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati 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; import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration; import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration; import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; @@ -71,6 +74,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.ResolvableType; import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.jdbc.core.JdbcTemplate; @@ -84,11 +88,12 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; * @author Stephane Nicoll * @author Phillip Webb * @author Tommy Ludwig + * @author Eddú Meléndez * @since 1.1.0 */ @Configuration @AutoConfigureBefore({ EndpointAutoConfiguration.class }) -@AutoConfigureAfter({ CassandraAutoConfiguration.class, +@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, DataSourceAutoConfiguration.class, MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, RedisAutoConfiguration.class, RabbitAutoConfiguration.class, @@ -176,6 +181,24 @@ public class HealthIndicatorAutoConfiguration { } + @Configuration + @ConditionalOnClass({ CouchbaseOperations.class, Bucket.class}) + @ConditionalOnBean(CouchbaseOperations.class) + @ConditionalOnEnabledHealthIndicator("couchbase") + public static class CouchbaseHealthIndicatorConfiguration extends + CompositeHealthIndicatorConfiguration { + + @Autowired + private Map couchbaseOperations; + + @Bean + @ConditionalOnMissingBean(name = "couchbaseHealthIndicator") + public HealthIndicator couchbaseHealthIndicator() { + return createHealthIndicator(this.couchbaseOperations); + } + + } + @Configuration @ConditionalOnClass(JdbcTemplate.class) @ConditionalOnBean(DataSource.class) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java new file mode 100644 index 00000000000..fbff1aa80f1 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java @@ -0,0 +1,47 @@ +/* + * 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.actuate.health; + +import java.util.List; + +import com.couchbase.client.java.util.features.Version; + +import org.springframework.data.couchbase.core.CouchbaseOperations; +import org.springframework.util.Assert; + +/** + * {@link HealthIndicator} for Couchbase. + * + * @author Eddú Meléndez + * @since 1.4.0 + */ +public class CouchbaseHealthIndicator extends AbstractHealthIndicator { + + private CouchbaseOperations couchbaseOperations; + + public CouchbaseHealthIndicator(CouchbaseOperations couchbaseOperations) { + Assert.notNull(couchbaseOperations, "CouchbaseOperations must not be null"); + this.couchbaseOperations = couchbaseOperations; + } + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + List versions = this.couchbaseOperations.getCouchbaseClusterInfo().getAllVersions(); + builder.up().withDetail("version", versions.get(0).toString()); + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java index d5dbcd4d5b4..bb082b07f86 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.actuate.health.CassandraHealthIndicator; +import org.springframework.boot.actuate.health.CouchbaseHealthIndicator; import org.springframework.boot.actuate.health.DataSourceHealthIndicator; import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator; import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator; @@ -56,6 +57,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.couchbase.core.CouchbaseOperations; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -66,6 +68,7 @@ import static org.mockito.Mockito.mock; * @author Christian Dupuis * @author Stephane Nicoll * @author Andy Wilkinson + * @author Eddú Meléndez */ public class HealthIndicatorAutoConfigurationTests { @@ -436,6 +439,19 @@ public class HealthIndicatorAutoConfigurationTests { .isEqualTo(CassandraHealthIndicator.class); } + @Test + public void couchbaseHealthIndicator() throws Exception { + EnvironmentTestUtils.addEnvironment(this.context, + "management.health.diskspace.enabled:false"); + this.context.register(CouchbaseConfiguration.class, + ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); + this.context.refresh(); + Map beans = this.context + .getBeansOfType(HealthIndicator.class); + assertThat(beans.size()).isEqualTo(1); + assertThat(beans.values().iterator().next().getClass()).isEqualTo(CouchbaseHealthIndicator.class); + } + @Configuration @EnableConfigurationProperties protected static class DataSourceConfig { @@ -476,4 +492,15 @@ public class HealthIndicatorAutoConfigurationTests { } + @Configuration + protected static class CouchbaseConfiguration { + + @Bean + public CouchbaseOperations couchbaseOperations() { + CouchbaseOperations operations = mock(CouchbaseOperations.class); + return operations; + } + + } + } diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index 4500ac787c9..95a8622bef2 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -325,6 +325,17 @@ spring-batch-core true + + org.springframework.data + spring-data-couchbase + true + + + org.slf4j + jcl-over-slf4j + + + org.springframework.data spring-data-jpa 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 new file mode 100644 index 00000000000..3825d746477 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfiguration.java @@ -0,0 +1,77 @@ +/* + * 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.Arrays; +import java.util.List; + +import javax.validation.Validator; + +import com.couchbase.client.java.CouchbaseBucket; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +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.mapping.event.ValidatingCouchbaseEventListener; + +/** + * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration + * Auto-Configuration} for Couchbase. + * + * @author Eddú Meléndez + * @since 1.4.0 + */ +@Configuration +@ConditionalOnClass({ CouchbaseBucket.class, CouchbaseBucketFactoryBean.class }) +@EnableConfigurationProperties(CouchbaseProperties.class) +public class CouchbaseAutoConfiguration { + + @Bean + @ConditionalOnBean(Validator.class) + public ValidatingCouchbaseEventListener validationEventListener(Validator validator) { + return new ValidatingCouchbaseEventListener(validator); + } + + @Configuration + static class CouchbaseConfiguration extends AbstractCouchbaseConfiguration { + + @Autowired + private CouchbaseProperties properties; + + @Override + protected List getBootstrapHosts() { + return Arrays.asList(this.properties.getHosts()); + } + + @Override + protected String getBucketName() { + return this.properties.getBucketName(); + } + + @Override + protected String getBucketPassword() { + return this.properties.getBucketPassword(); + } + + } + +} 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 new file mode 100644 index 00000000000..96e8d310dd5 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java @@ -0,0 +1,69 @@ +/* + * 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.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Couchbase. + * + * @author Eddú Meléndez + * @since 1.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.couchbase") +public class CouchbaseProperties { + + /** + * Couchabase server hosts. + */ + private String[] hosts; + + /** + * Couchbase bucket name. + */ + private String bucketName; + + /** + * Couchbase bucket password. + */ + private String bucketPassword; + + public String[] getHosts() { + return this.hosts; + } + + public void setHosts(String[] hosts) { + this.hosts = hosts; + } + + public String getBucketName() { + return this.bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getBucketPassword() { + return this.bucketPassword; + } + + public void setBucketPassword(String bucketPassword) { + this.bucketPassword = bucketPassword; + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/package-info.java new file mode 100644 index 00000000000..8d930f10d57 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * Auto-configuration for Couchbase. + */ +package org.springframework.boot.autoconfigure.couchbase; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java new file mode 100644 index 00000000000..f13a5d606c0 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java @@ -0,0 +1,44 @@ +/* + * 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 org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.repository.CouchbaseRepository; +import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase + * Repositories. + * + * @author Eddú Meléndez + * @since 1.4.0 + */ +@Configuration +@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class }) +@ConditionalOnProperty(prefix = "spring.data.couchbase.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnMissingBean(CouchbaseRepositoryFactoryBean.class) +@Import(CouchbaseRepositoriesRegistrar.class) +public class CouchbaseRepositoriesAutoConfiguration { + +} 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 new file mode 100644 index 00000000000..bd52fcbf261 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java @@ -0,0 +1,56 @@ +/* + * 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 java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension; +import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Couchbase + * Repositories. + * + * @author Eddú Meléndez + * @since 1.4.0 + */ +public class CouchbaseRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableCouchbaseRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableCouchbaseRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new CouchbaseRepositoryConfigurationExtension(); + } + + @EnableCouchbaseRepositories + private static class EnableCouchbaseRepositoriesConfiguration { + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java new file mode 100644 index 00000000000..bba40726b58 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * Auto-configuration for Spring Data Couchbase. + */ +package org.springframework.boot.autoconfigure.data.couchbase; 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 3ca9810ebe0..da4b6b5eb7a 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -19,9 +19,11 @@ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ +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.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ 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 new file mode 100644 index 00000000000..73b5d82340e --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationTests.java @@ -0,0 +1,62 @@ +/* + * 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.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * Tests for {@link CouchbaseAutoConfiguration} + * + * @author Eddú Meléndez + */ +public class CouchbaseAutoConfigurationTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void validateProperties() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.couchbase.hosts=localhost", + "spring.data.couchbase.bucket-name=test", + "spring.data.couchbase.bucket-password=test"); + this.context.register(PropertyPlaceholderAutoConfiguration.class, + CouchbaseAutoConfiguration.class); + this.thrown.expect(BeanCreationException.class); + this.thrown.expectMessage("Connection refused"); + this.context.refresh(); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java new file mode 100644 index 00000000000..5abd9020c95 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java @@ -0,0 +1,26 @@ +/* + * 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.alt.couchbase; + +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.data.repository.Repository; + +/** + * @author Eddú Meléndez + */ +public interface CityCouchbaseRepository extends Repository { +} 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 new file mode 100644 index 00000000000..b8c12810532 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java @@ -0,0 +1,157 @@ +/* + * 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 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; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.cluster.ClusterInfo; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +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.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.WriteResultChecking; +import org.springframework.data.couchbase.core.query.Consistency; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * @author Eddú Meléndez + */ +public class CouchbaseRepositoriesAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + this.context.close(); + } + + @Test + public void testDefaultRepositoryConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + addCouchbaseProperties(this.context); + this.context.register(TestConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBean(CityRepository.class)).isNotNull(); + assertThat(this.context.getBean(Bucket.class)).isNotNull(); + } + + @Test + public void testNoRepositoryConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + addCouchbaseProperties(this.context); + this.context.register(EmptyConfiguration.class, TestConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBean(Bucket.class)).isNotNull(); + } + + @Test + public void templateExists() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.couchbase.hosts=localhost", + "spring.data.couchbase.bucket-name=test", + "spring.data.couchbase.bucket-password=test"); + this.context.register(PropertyPlaceholderAutoConfiguration.class, + TestConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBeanNamesForType(CouchbaseTemplate.class).length).isEqualTo(1); + } + + private void addCouchbaseProperties(AnnotationConfigApplicationContext context) { + EnvironmentTestUtils.addEnvironment(context, + "spring.data.couchbase.hosts=localhost", + "spring.data.couchbase.bucket-name=test", + "spring.data.couchbase.bucket-password=test"); + } + + @Configuration + @TestAutoConfigurationPackage(City.class) + @Import(CouchbaseRepositoriesRegistrar.class) + static class TestConfiguration extends AbstractCouchbaseConfiguration { + + @Override + protected List getBootstrapHosts() { + return Collections.singletonList("192.1.2.3"); + } + + @Override + protected String getBucketName() { + return "someBucket"; + } + + @Override + protected String getBucketPassword() { + return "someBucketPassword"; + } + + @Override + public Cluster couchbaseCluster() throws Exception { + return mock(CouchbaseCluster.class); + } + + @Bean + public ClusterInfo couchbaseClusterInfo() { + return mock(ClusterInfo.class); + } + + @Override + public Bucket couchbaseClient() throws Exception { + return mock(CouchbaseBucket.class); + } + + @Override + public CouchbaseTemplate couchbaseTemplate() throws Exception { + CouchbaseTemplate template = super.couchbaseTemplate(); + template.setWriteResultChecking(WriteResultChecking.LOG); + return template; + } + + @Override + protected Consistency getDefaultConsistency() { + return Consistency.READ_YOUR_OWN_WRITES; + } + + } + + @Configuration + @TestAutoConfigurationPackage(EmptyDataPackage.class) + protected static class EmptyConfiguration { + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java new file mode 100644 index 00000000000..0b0659a1143 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java @@ -0,0 +1,33 @@ +/* + * 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.city; + +import com.couchbase.client.java.repository.annotation.Field; +import com.couchbase.client.java.repository.annotation.Id; + +import org.springframework.data.couchbase.core.mapping.Document; + +@Document +public class City { + + @Id + private String id; + + @Field + private String name; + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java new file mode 100644 index 00000000000..d3d36ef701f --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java @@ -0,0 +1,23 @@ +/* + * 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.city; + +import org.springframework.data.repository.Repository; + +public interface CityRepository extends Repository { + +} diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index aba773bd98e..1a16b61bedf 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -271,6 +271,11 @@ spring-boot-starter-data-cassandra 1.4.0.BUILD-SNAPSHOT + + org.springframework.boot + spring-boot-starter-data-couchbase + 1.4.0.BUILD-SNAPSHOT + org.springframework.boot spring-boot-starter-data-elasticsearch @@ -1790,12 +1795,23 @@ + + org.springframework.data + spring-data-couchbase + ${spring-data-couchbase.version} + org.springframework.data spring-data-releasetrain ${spring-data-releasetrain.version} import pom + + + org.springframework.data + spring-data-couchbase + + org.springframework.hateoas @@ -2239,4 +2255,4 @@ integration-test - \ No newline at end of file + 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 9284eb8d007..2c1d35f9c2f 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -488,6 +488,11 @@ 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]) + spring.data.couchbase.hosts= # the db host + spring.data.couchbase.bucket-name= # the bucket name + spring.data.couchbase.bucket-password= # the bucket password + # ELASTICSEARCH ({sc-spring-boot-autoconfigure}/elasticsearch/ElasticsearchProperties.{sc-ext}[ElasticsearchProperties]) spring.data.elasticsearch.cluster-name=elasticsearch # Elasticsearch cluster name. spring.data.elasticsearch.cluster-nodes= # Comma-separated list of cluster node addresses. If not specified, starts a client node. diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc index 469eedb13e5..551b8252836 100644 --- a/spring-boot-samples/README.adoc +++ b/spring-boot-samples/README.adoc @@ -60,6 +60,8 @@ -- Example showing message-oriented application using HornetQ * link:spring-boot-sample-batch[spring-boot-sample-batch] -- Define and run a Batch job in a few lines of code +* link:spring-boot-sample-data-couchbase[spring-boot-sample-data-couchbase] + -- Spring Data Couchbase repositories * link:spring-boot-sample-data-jpa[spring-boot-sample-data-jpa] -- Spring Data JPA + Hibernate + HSQLDB * link:spring-boot-sample-data-mongodb[spring-boot-sample-data-mongodb] diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 4e7446eb03f..3fb2f76fa2b 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -33,6 +33,7 @@ spring-boot-sample-batch spring-boot-sample-cache spring-boot-sample-data-cassandra + spring-boot-sample-data-couchbase spring-boot-sample-data-elasticsearch spring-boot-sample-data-gemfire spring-boot-sample-data-jpa diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/pom.xml b/spring-boot-samples/spring-boot-sample-data-couchbase/pom.xml new file mode 100644 index 00000000000..32c98431e9e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + spring-boot-samples + org.springframework.boot + 1.4.0.BUILD-SNAPSHOT + + spring-boot-sample-data-couchbase + Spring Boot Data Couchbase Sample + Spring Boot Data Couchbase Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-couchbase + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + 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 new file mode 100644 index 00000000000..dcd32062fac --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/SampleCouchbaseApplication.java @@ -0,0 +1,49 @@ +/* + * 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 sample.data.couchbase; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleCouchbaseApplication implements CommandLineRunner { + + @Autowired + private UserRepository userRepository; + + public static void main(String[] args) { + SpringApplication.run(SampleCouchbaseApplication.class); + } + + @Override + public void run(String... args) throws Exception { + saveUsers(); + + System.out.println(this.userRepository.findAll()); + } + + private void saveUsers() { + User user = new User(); + user.setFirstname("Alice"); + user.setLastname("Smith"); + + this.userRepository.save(user); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java new file mode 100644 index 00000000000..5895000d749 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java @@ -0,0 +1,68 @@ +/* + * 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 sample.data.couchbase; + + +import com.couchbase.client.java.repository.annotation.Field; +import com.couchbase.client.java.repository.annotation.Id; +import org.springframework.data.couchbase.core.mapping.Document; + +@Document +public class User { + + @Id + private String id; + + @Field + private String firstname; + + @Field + private String lastname; + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFirstname() { + return this.firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return this.lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + @Override + public String toString() { + return "User{" + + "id='" + this.id + '\'' + + ", firstname='" + this.firstname + '\'' + + ", lastname='" + this.lastname + '\'' + + '}'; + } +} 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 new file mode 100644 index 00000000000..1e2deab5bc0 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/UserRepository.java @@ -0,0 +1,23 @@ +/* + * 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 sample.data.couchbase; + +import org.springframework.data.couchbase.repository.CouchbaseRepository; + +public interface UserRepository extends CouchbaseRepository { + +} diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java new file mode 100644 index 00000000000..7063a439b87 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java @@ -0,0 +1,47 @@ +package sample.data.couchbase; + +import java.net.ConnectException; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.test.OutputCapture; +import org.springframework.core.NestedCheckedException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SampleCouchbaseApplicationTests { + + @Rule + public OutputCapture outputCapture = new OutputCapture(); + + @Test + public void testDefaultSettings() throws Exception { + try { + new SpringApplicationBuilder(SampleCouchbaseApplication.class) + .run(); + } + catch (RuntimeException ex) { + if (serverNotRunning(ex)) { + return; + } + } + String output = this.outputCapture.toString(); + assertThat(output).contains("firstname='Alice', lastname='Smith'"); + } + + private boolean serverNotRunning(RuntimeException ex) { + @SuppressWarnings("serial") + NestedCheckedException nested = new NestedCheckedException("failed", ex) { + }; + if (nested.contains(ConnectException.class)) { + Throwable root = nested.getRootCause(); + if (root.getMessage().contains("Connection refused")) { + return true; + } + } + return false; + } + +} 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 new file mode 100644 index 00000000000..d8adb02adfc --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/resources/application.properties @@ -0,0 +1,3 @@ +spring.data.couchbase.bucket-name=mybucket +spring.data.couchbase.bucket-password=couchbase +spring.data.couchbase.hosts[0]=127.0.0.1 diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml index c7552423324..e5667e3c3a5 100644 --- a/spring-boot-starters/pom.xml +++ b/spring-boot-starters/pom.xml @@ -28,6 +28,7 @@ spring-boot-starter-cache spring-boot-starter-cloud-connectors spring-boot-starter-data-cassandra + spring-boot-starter-data-couchbase spring-boot-starter-data-elasticsearch spring-boot-starter-data-gemfire spring-boot-starter-data-jpa diff --git a/spring-boot-starters/spring-boot-starter-data-couchbase/pom.xml b/spring-boot-starters/spring-boot-starter-data-couchbase/pom.xml new file mode 100644 index 00000000000..938e7e5e234 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-data-couchbase/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + spring-boot-starters + org.springframework.boot + 1.4.0.BUILD-SNAPSHOT + + spring-boot-starter-data-couchbase + Spring Boot Data Couchbase Starter + Spring Boot Data Couchbase Starter + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.data + spring-data-couchbase + + + diff --git a/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides b/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides new file mode 100644 index 00000000000..7eb2d6ff979 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-data-couchbase/src/main/resources/META-INF/spring.provides @@ -0,0 +1 @@ +provides: spring-data-couchbase From da3b49e0247e85dbb10eda2b6b45e10de26f0dbd Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 15 Feb 2016 20:25:12 +0100 Subject: [PATCH 2/2] Polish contribution Closes gh-3499 --- .../HealthIndicatorAutoConfiguration.java | 13 +-- .../health/CouchbaseHealthIndicator.java | 3 +- .../couchbase/CouchbaseAutoConfiguration.java | 37 ++++++-- .../couchbase/CouchbaseProperties.java | 64 ++++++++------ .../CouchbaseAutoConfigurationTests.java | 72 +++++++++++++--- .../couchbase/CouchbaseTestConfiguration.java | 72 ++++++++++++++++ ...aseRepositoriesAutoConfigurationTests.java | 84 +------------------ spring-boot-dependencies/pom.xml | 11 --- .../appendix-application-properties.adoc | 6 +- .../main/asciidoc/spring-boot-features.adoc | 60 +++++++++++++ .../README.adoc | 22 +++++ .../couchbase/SampleCouchbaseApplication.java | 7 +- .../main/java/sample/data/couchbase/User.java | 24 +++--- .../SampleCouchbaseApplicationTests.java | 2 +- .../src/test/resources/application.properties | 5 +- 15 files changed, 320 insertions(+), 162 deletions(-) create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfiguration.java create mode 100644 spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java index 6d9a482f58c..38eb079ca64 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java @@ -93,12 +93,13 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; */ @Configuration @AutoConfigureBefore({ EndpointAutoConfiguration.class }) -@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, CassandraAutoConfiguration.class, - CassandraDataAutoConfiguration.class, DataSourceAutoConfiguration.class, - MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, - RedisAutoConfiguration.class, RabbitAutoConfiguration.class, - SolrAutoConfiguration.class, MailSenderAutoConfiguration.class, - JmsAutoConfiguration.class, ElasticsearchAutoConfiguration.class }) +@AutoConfigureAfter({ CassandraAutoConfiguration.class, + CassandraDataAutoConfiguration.class, CouchbaseAutoConfiguration.class, + DataSourceAutoConfiguration.class, MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, RedisAutoConfiguration.class, + RabbitAutoConfiguration.class, SolrAutoConfiguration.class, + MailSenderAutoConfiguration.class, JmsAutoConfiguration.class, + ElasticsearchAutoConfiguration.class }) @EnableConfigurationProperties({ HealthIndicatorAutoConfigurationProperties.class }) public class HealthIndicatorAutoConfiguration { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java index fbff1aa80f1..ae4e0f7c432 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/CouchbaseHealthIndicator.java @@ -22,6 +22,7 @@ import com.couchbase.client.java.util.features.Version; import org.springframework.data.couchbase.core.CouchbaseOperations; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * {@link HealthIndicator} for Couchbase. @@ -41,7 +42,7 @@ public class CouchbaseHealthIndicator extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { List versions = this.couchbaseOperations.getCouchbaseClusterInfo().getAllVersions(); - builder.up().withDetail("version", versions.get(0).toString()); + builder.up().withDetail("versions", StringUtils.collectionToCommaDelimitedString(versions)); } } 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 3825d746477..df6e889f1c0 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,7 +16,6 @@ package org.springframework.boot.autoconfigure.couchbase; -import java.util.Arrays; import java.util.List; import javax.validation.Validator; @@ -24,10 +23,14 @@ import javax.validation.Validator; import com.couchbase.client.java.CouchbaseBucket; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; 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.condition.ConditionalOnProperty; 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.config.CouchbaseBucketFactoryBean; @@ -38,10 +41,12 @@ import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbase * Auto-Configuration} for Couchbase. * * @author Eddú Meléndez + * @author Stephane Nicoll * @since 1.4.0 */ @Configuration -@ConditionalOnClass({ CouchbaseBucket.class, CouchbaseBucketFactoryBean.class }) +@ConditionalOnClass({CouchbaseBucket.class, CouchbaseBucketFactoryBean.class}) +@Conditional(CouchbaseAutoConfiguration.CouchbaseCondition.class) @EnableConfigurationProperties(CouchbaseProperties.class) public class CouchbaseAutoConfiguration { @@ -52,24 +57,44 @@ public class CouchbaseAutoConfiguration { } @Configuration - static class CouchbaseConfiguration extends AbstractCouchbaseConfiguration { + @ConditionalOnMissingBean(AbstractCouchbaseConfiguration.class) + public static class CouchbaseConfiguration extends AbstractCouchbaseConfiguration { @Autowired private CouchbaseProperties properties; @Override protected List getBootstrapHosts() { - return Arrays.asList(this.properties.getHosts()); + return this.properties.getBootstrapHosts(); } @Override protected String getBucketName() { - return this.properties.getBucketName(); + return this.properties.getBucket().getName(); } @Override protected String getBucketPassword() { - return this.properties.getBucketPassword(); + return 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. + */ + static class CouchbaseCondition extends AnyNestedCondition { + + CouchbaseCondition() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnProperty(prefix = "spring.data.couchbase.bucket", name = "name") + static class BucketNameProperty { + } + + @ConditionalOnBean(AbstractCouchbaseConfiguration.class) + static class CouchbaseConfiguration { } } 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 96e8d310dd5..a7b6f755077 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,54 +16,68 @@ 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; /** * Configuration properties for Couchbase. * * @author Eddú Meléndez + * @author Stephane Nicoll * @since 1.4.0 */ @ConfigurationProperties(prefix = "spring.data.couchbase") public class CouchbaseProperties { /** - * Couchabase server hosts. + * Couchbase nodes (host or IP address) to bootstrap from. */ - private String[] hosts; + private List bootstrapHosts = new ArrayList(Collections.singletonList("localhost")); - /** - * Couchbase bucket name. - */ - private String bucketName; + private final Bucket bucket = new Bucket(); - /** - * Couchbase bucket password. - */ - private String bucketPassword; - - public String[] getHosts() { - return this.hosts; + public List getBootstrapHosts() { + return this.bootstrapHosts; } - public void setHosts(String[] hosts) { - this.hosts = hosts; + public void setBootstrapHosts(List bootstrapHosts) { + this.bootstrapHosts = bootstrapHosts; } - public String getBucketName() { - return this.bucketName; + public Bucket getBucket() { + return this.bucket; } - public void setBucketName(String bucketName) { - this.bucketName = bucketName; - } + static class Bucket { - public String getBucketPassword() { - return this.bucketPassword; - } + /** + * Name of the bucket to connect to. + */ + private String name; - public void setBucketPassword(String bucketPassword) { - this.bucketPassword = bucketPassword; + /** + * Password of the bucket. + */ + private String password = ""; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } } } 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 73b5d82340e..35e23b434c6 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,15 +16,27 @@ package org.springframework.boot.autoconfigure.couchbase; +import javax.validation.Validator; + +import com.couchbase.client.java.Bucket; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.springframework.beans.factory.BeanCreationException; +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 static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; /** * Tests for {@link CouchbaseAutoConfiguration} @@ -46,17 +58,55 @@ public class CouchbaseAutoConfigurationTests { } @Test - public void validateProperties() { - this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.couchbase.hosts=localhost", - "spring.data.couchbase.bucket-name=test", - "spring.data.couchbase.bucket-password=test"); - this.context.register(PropertyPlaceholderAutoConfiguration.class, + public void bucketNameIsRequired() { + load(null); + assertThat(this.context.getBeansOfType(CouchbaseTemplate.class)).isEmpty(); + assertThat(this.context.getBeansOfType(Bucket.class)).isEmpty(); + assertThat(this.context.getBeansOfType(ValidatingCouchbaseEventListener.class)).isEmpty(); + } + + @Test + public void bucketNameIsNotRequiredIfCustomConfigurationIsSpecified() throws Exception { + load(CouchbaseTestConfiguration.class); + + assertThat(this.context.getBeansOfType(AbstractCouchbaseConfiguration.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)); + } + + 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); - this.thrown.expect(BeanCreationException.class); - this.thrown.expectMessage("Connection refused"); - this.context.refresh(); + context.refresh(); + this.context = context; + } + + @Configuration + @Import(CouchbaseTestConfiguration.class) + static class ValidatorConfiguration { + + @Bean + public Validator myValidator() { + return mock(Validator.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 new file mode 100644 index 00000000000..2d938584318 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseTestConfiguration.java @@ -0,0 +1,72 @@ +/* + * 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.Collections; +import java.util.List; + +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 org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; + +import static org.mockito.Mockito.mock; + +/** + * Test configuration for couchbase that mocks access. + * + * @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"; + } + + @Override + public Cluster couchbaseCluster() throws Exception { + return mock(CouchbaseCluster.class); + } + + @Bean + public ClusterInfo couchbaseClusterInfo() { + return mock(ClusterInfo.class); + } + + @Override + public Bucket couchbaseClient() throws Exception { + return mock(CouchbaseBucket.class); + } + +} 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 b8c12810532..8ab1d4e4a06 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 @@ -16,35 +16,21 @@ package org.springframework.boot.autoconfigure.data.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; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.cluster.ClusterInfo; - import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +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.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.WriteResultChecking; -import org.springframework.data.couchbase.core.query.Consistency; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; /** * @author Eddú Meléndez @@ -61,7 +47,6 @@ public class CouchbaseRepositoriesAutoConfigurationTests { @Test public void testDefaultRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - addCouchbaseProperties(this.context); this.context.register(TestConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); @@ -72,79 +57,16 @@ public class CouchbaseRepositoriesAutoConfigurationTests { @Test public void testNoRepositoryConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); - addCouchbaseProperties(this.context); this.context.register(EmptyConfiguration.class, TestConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(Bucket.class)).isNotNull(); } - @Test - public void templateExists() { - this.context = new AnnotationConfigApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.couchbase.hosts=localhost", - "spring.data.couchbase.bucket-name=test", - "spring.data.couchbase.bucket-password=test"); - this.context.register(PropertyPlaceholderAutoConfiguration.class, - TestConfiguration.class); - this.context.refresh(); - assertThat(this.context.getBeanNamesForType(CouchbaseTemplate.class).length).isEqualTo(1); - } - - private void addCouchbaseProperties(AnnotationConfigApplicationContext context) { - EnvironmentTestUtils.addEnvironment(context, - "spring.data.couchbase.hosts=localhost", - "spring.data.couchbase.bucket-name=test", - "spring.data.couchbase.bucket-password=test"); - } - @Configuration @TestAutoConfigurationPackage(City.class) - @Import(CouchbaseRepositoriesRegistrar.class) - static class TestConfiguration extends AbstractCouchbaseConfiguration { - - @Override - protected List getBootstrapHosts() { - return Collections.singletonList("192.1.2.3"); - } - - @Override - protected String getBucketName() { - return "someBucket"; - } - - @Override - protected String getBucketPassword() { - return "someBucketPassword"; - } - - @Override - public Cluster couchbaseCluster() throws Exception { - return mock(CouchbaseCluster.class); - } - - @Bean - public ClusterInfo couchbaseClusterInfo() { - return mock(ClusterInfo.class); - } - - @Override - public Bucket couchbaseClient() throws Exception { - return mock(CouchbaseBucket.class); - } - - @Override - public CouchbaseTemplate couchbaseTemplate() throws Exception { - CouchbaseTemplate template = super.couchbaseTemplate(); - template.setWriteResultChecking(WriteResultChecking.LOG); - return template; - } - - @Override - protected Consistency getDefaultConsistency() { - return Consistency.READ_YOUR_OWN_WRITES; - } + @Import({ CouchbaseRepositoriesRegistrar.class, CouchbaseTestConfiguration.class }) + static class TestConfiguration { } diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 1a16b61bedf..0b8947cf887 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -1795,23 +1795,12 @@ - - org.springframework.data - spring-data-couchbase - ${spring-data-couchbase.version} - org.springframework.data spring-data-releasetrain ${spring-data-releasetrain.version} import pom - - - org.springframework.data - spring-data-couchbase - - org.springframework.hateoas 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 2c1d35f9c2f..49ddc578785 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -489,9 +489,9 @@ 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.hosts= # the db host - spring.data.couchbase.bucket-name= # the bucket name - spring.data.couchbase.bucket-password= # the bucket password + 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. # ELASTICSEARCH ({sc-spring-boot-autoconfigure}/elasticsearch/ElasticsearchProperties.{sc-ext}[ElasticsearchProperties]) spring.data.elasticsearch.cluster-name=elasticsearch # Elasticsearch cluster name. 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 a574c2fa9c6..08ac5d37ac6 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3122,6 +3122,66 @@ TIP: For complete details of Spring Data Cassandra, refer to their http://docs.spring.io/spring-data/cassandra/docs/[reference documentation]. +[[boot-features-couchbase]] +=== Couchbase +http://www.couchbase.com/[Couchbase] is an open-source, distributed multi-model NoSQL +document-oriented database that is optimized for interactive applications. Spring Boot +offers auto-configuration for Couchbase and abstractions on top of it provided by +https://github.com/spring-projects/spring-data-couchbase[Spring Data Couchbase]. +There is a `spring-boot-starter-data-couchbase` '`Starter POM`' for collecting the +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 +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 +---- + +[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. +==== + +[source,java,indent=0] +---- + @Component + public class MyBean { + + private final CouchbaseTemplate template; + + @Autowired + public MyBean(CouchbaseTemplate template) { + this.template = template; + } + + // ... + + } +---- + +If you add a `@Bean` of your own of type `CassandraTemplate` it 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 diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc b/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc new file mode 100644 index 00000000000..1a0058bd9c5 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/README.adoc @@ -0,0 +1,22 @@ += Spring Boot Couchbase Sample + +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`. + +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: + +```java +function (doc, meta) { + if (doc._class == "sample.data.couchbase.User") { + emit(meta.id, null); + } +} +``` + +and the _reduce_ function to `_count`. After you've saved your changes go back to `Views` +and click on `Publish` so that the `all` view move to the `Production Views` tab. \ No newline at end of file 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 dcd32062fac..4ba3ab45493 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 @@ -16,6 +16,8 @@ package sample.data.couchbase; +import java.util.UUID; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -40,8 +42,9 @@ public class SampleCouchbaseApplication implements CommandLineRunner { private void saveUsers() { User user = new User(); - user.setFirstname("Alice"); - user.setLastname("Smith"); + user.setId(UUID.randomUUID().toString()); + user.setFirstName("Alice"); + user.setLastName("Smith"); this.userRepository.save(user); } diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java index 5895000d749..88a7a659d51 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/main/java/sample/data/couchbase/User.java @@ -28,10 +28,10 @@ public class User { private String id; @Field - private String firstname; + private String firstName; @Field - private String lastname; + private String lastName; public String getId() { return this.id; @@ -41,28 +41,28 @@ public class User { this.id = id; } - public String getFirstname() { - return this.firstname; + public String getFirstName() { + return this.firstName; } - public void setFirstname(String firstname) { - this.firstname = firstname; + public void setFirstName(String firstName) { + this.firstName = firstName; } - public String getLastname() { - return this.lastname; + public String getLastName() { + return this.lastName; } - public void setLastname(String lastname) { - this.lastname = lastname; + public void setLastName(String lastName) { + this.lastName = lastName; } @Override public String toString() { return "User{" + "id='" + this.id + '\'' + - ", firstname='" + this.firstname + '\'' + - ", lastname='" + this.lastname + '\'' + + ", firstName='" + this.firstName + '\'' + + ", lastName='" + this.lastName + '\'' + '}'; } } diff --git a/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java index 7063a439b87..79e920d2589 100644 --- a/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-data-couchbase/src/test/java/sample/data/couchbase/SampleCouchbaseApplicationTests.java @@ -28,7 +28,7 @@ public class SampleCouchbaseApplicationTests { } } String output = this.outputCapture.toString(); - assertThat(output).contains("firstname='Alice', lastname='Smith'"); + assertThat(output).contains("firstName='Alice', lastName='Smith'"); } private boolean serverNotRunning(RuntimeException ex) { 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 d8adb02adfc..774aeb9a18d 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,3 +1,2 @@ -spring.data.couchbase.bucket-name=mybucket -spring.data.couchbase.bucket-password=couchbase -spring.data.couchbase.hosts[0]=127.0.0.1 +spring.data.couchbase.bucket.name=mybucket +spring.data.couchbase.bucket.password=couchbase \ No newline at end of file