Commit a43b0232 authored by Stephane Nicoll's avatar Stephane Nicoll

Merge pull request #3499 from eddumelendez/gh-3498

* pr/3499:
  Polish contribution
  Add Couchbase support
parents ecf11e02 da3b49e0
......@@ -151,6 +151,11 @@
<artifactId>spring-data-cassandra</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
......
......@@ -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,16 +88,18 @@ 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,
CassandraDataAutoConfiguration.class, DataSourceAutoConfiguration.class,
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
RedisAutoConfiguration.class, RabbitAutoConfiguration.class,
SolrAutoConfiguration.class, MailSenderAutoConfiguration.class,
JmsAutoConfiguration.class, ElasticsearchAutoConfiguration.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 {
......@@ -176,6 +182,24 @@ public class HealthIndicatorAutoConfiguration {
}
@Configuration
@ConditionalOnClass({ CouchbaseOperations.class, Bucket.class})
@ConditionalOnBean(CouchbaseOperations.class)
@ConditionalOnEnabledHealthIndicator("couchbase")
public static class CouchbaseHealthIndicatorConfiguration extends
CompositeHealthIndicatorConfiguration<CouchbaseHealthIndicator, CouchbaseOperations> {
@Autowired
private Map<String, CouchbaseOperations> couchbaseOperations;
@Bean
@ConditionalOnMissingBean(name = "couchbaseHealthIndicator")
public HealthIndicator couchbaseHealthIndicator() {
return createHealthIndicator(this.couchbaseOperations);
}
}
@Configuration
@ConditionalOnClass(JdbcTemplate.class)
@ConditionalOnBean(DataSource.class)
......
/*
* 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;
import org.springframework.util.StringUtils;
/**
* {@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<Version> versions = this.couchbaseOperations.getCouchbaseClusterInfo().getAllVersions();
builder.up().withDetail("versions", StringUtils.collectionToCommaDelimitedString(versions));
}
}
......@@ -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<String, HealthIndicator> 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;
}
}
}
......@@ -325,6 +325,17 @@
<artifactId>spring-batch-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
......
/*
* 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.List;
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;
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-Configuration} for Couchbase.
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @since 1.4.0
*/
@Configuration
@ConditionalOnClass({CouchbaseBucket.class, CouchbaseBucketFactoryBean.class})
@Conditional(CouchbaseAutoConfiguration.CouchbaseCondition.class)
@EnableConfigurationProperties(CouchbaseProperties.class)
public class CouchbaseAutoConfiguration {
@Bean
@ConditionalOnBean(Validator.class)
public ValidatingCouchbaseEventListener validationEventListener(Validator validator) {
return new ValidatingCouchbaseEventListener(validator);
}
@Configuration
@ConditionalOnMissingBean(AbstractCouchbaseConfiguration.class)
public static class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
@Autowired
private CouchbaseProperties properties;
@Override
protected List<String> getBootstrapHosts() {
return this.properties.getBootstrapHosts();
}
@Override
protected String getBucketName() {
return this.properties.getBucket().getName();
}
@Override
protected String 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 {
}
}
}
/*
* 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.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 {
/**
* Couchbase nodes (host or IP address) to bootstrap from.
*/
private List<String> bootstrapHosts = new ArrayList<String>(Collections.singletonList("localhost"));
private final Bucket bucket = new Bucket();
public List<String> getBootstrapHosts() {
return this.bootstrapHosts;
}
public void setBootstrapHosts(List<String> bootstrapHosts) {
this.bootstrapHosts = bootstrapHosts;
}
public Bucket getBucket() {
return this.bucket;
}
static class Bucket {
/**
* Name of the bucket to connect to.
*/
private String name;
/**
* 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;
}
}
}
/*
* 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;
/*
* 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 {
}
/*
* 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<? extends Annotation> getAnnotation() {
return EnableCouchbaseRepositories.class;
}
@Override
protected Class<?> getConfiguration() {
return EnableCouchbaseRepositoriesConfiguration.class;
}
@Override
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
return new CouchbaseRepositoryConfigurationExtension();
}
@EnableCouchbaseRepositories
private static class EnableCouchbaseRepositoriesConfiguration {
}
}
/*
* 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;
......@@ -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,\
......
/*
* 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 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.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}
*
* @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 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);
context.refresh();
this.context = context;
}
@Configuration
@Import(CouchbaseTestConfiguration.class)
static class ValidatorConfiguration {
@Bean
public Validator myValidator() {
return mock(Validator.class);
}
}
}
/*
* 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<String> 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);
}
}
/*
* 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<City, Long> {
}
/*
* 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.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.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @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();
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();
this.context.register(EmptyConfiguration.class, TestConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBean(Bucket.class)).isNotNull();
}
@Configuration
@TestAutoConfigurationPackage(City.class)
@Import({ CouchbaseRepositoriesRegistrar.class, CouchbaseTestConfiguration.class })
static class TestConfiguration {
}
@Configuration
@TestAutoConfigurationPackage(EmptyDataPackage.class)
protected static class EmptyConfiguration {
}
}
/*
* 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;
}
/*
* 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<City, Long> {
}
......@@ -271,6 +271,11 @@
<artifactId>spring-boot-starter-data-cassandra</artifactId>
<version>1.4.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
<version>1.4.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
......@@ -2239,4 +2244,4 @@
<id>integration-test</id>
</profile>
</profiles>
</project>
\ No newline at end of file
</project>
......@@ -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.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.
spring.data.elasticsearch.cluster-nodes= # Comma-separated list of cluster node addresses. If not specified, starts a client node.
......
......@@ -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
......
......@@ -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]
......
......@@ -33,6 +33,7 @@
<module>spring-boot-sample-batch</module>
<module>spring-boot-sample-cache</module>
<module>spring-boot-sample-data-cassandra</module>
<module>spring-boot-sample-data-couchbase</module>
<module>spring-boot-sample-data-elasticsearch</module>
<module>spring-boot-sample-data-gemfire</module>
<module>spring-boot-sample-data-jpa</module>
......
= 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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-boot-samples</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.4.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-data-couchbase</artifactId>
<name>Spring Boot Data Couchbase Sample</name>
<description>Spring Boot Data Couchbase Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* 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 java.util.UUID;
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.setId(UUID.randomUUID().toString());
user.setFirstName("Alice");
user.setLastName("Smith");
this.userRepository.save(user);
}
}
/*
* 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 + '\'' +
'}';
}
}
/*
* 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<User, String> {
}
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;
}
}
spring.data.couchbase.bucket.name=mybucket
spring.data.couchbase.bucket.password=couchbase
\ No newline at end of file
......@@ -28,6 +28,7 @@
<module>spring-boot-starter-cache</module>
<module>spring-boot-starter-cloud-connectors</module>
<module>spring-boot-starter-data-cassandra</module>
<module>spring-boot-starter-data-couchbase</module>
<module>spring-boot-starter-data-elasticsearch</module>
<module>spring-boot-starter-data-gemfire</module>
<module>spring-boot-starter-data-jpa</module>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-boot-starters</artifactId>
<groupId>org.springframework.boot</groupId>
<version>1.4.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-starter-data-couchbase</artifactId>
<name>Spring Boot Data Couchbase Starter</name>
<description>Spring Boot Data Couchbase Starter</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
</dependency>
</dependencies>
</project>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment