Upgrade to Couchbase SDK v3
This commit upgrades to the Couchbase SDK v3 which brings the following breaking changes: * Bootstrap hosts have been replaced by a connection string and the authentication is now mandatory. * A `Bucket` is no longer auto-configured. The `spring.couchbase.bucket.*` properties have been removed * `ClusterInfo` no longer exists and has been replaced by a dedicated API on `Cluster`. * `CouchbaseEnvironment` no longer exist in favour of `ClusterEnvironment`, the customizer has been renamed accordingly. * The bootstrap-related properties have been removed. Users requiring custom ports should supply the seed nodes and initialize a Cluster themselves. * The endpoints-related configuration has been consolidated in a single IO configuration. The Spring Data Couchbase provides an integration with the new SDK. This leads to the following changes: * A convenient `CouchbaseClientFactory` is auto-configured. * Repositories are configured against a bucket and a scope. Those can be set via configuration in `spring.data.couchbase.*`. * The default consistency property has been removed in favour of a more flexible annotation on the repository query methods instead. You can now specify different query consistency on a per method basis. * The `CacheManager` implementation is provided, as do other stores for consistency so a dependency on `couchbase-spring-cache` is no longer required. See gh-19893 Co-authored-by: Michael Nitschinger <michael@nitschinger.at>
This commit is contained in:
parent
e3899df22c
commit
abe43b2e83
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,13 +16,14 @@
|
|||
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.couchbase.client.core.message.internal.DiagnosticsReport;
|
||||
import com.couchbase.client.core.message.internal.EndpointHealth;
|
||||
import com.couchbase.client.core.state.LifecycleState;
|
||||
import com.couchbase.client.core.diagnostics.ClusterState;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
|
||||
|
@ -33,35 +34,29 @@ import org.springframework.boot.actuate.health.Health.Builder;
|
|||
*/
|
||||
class CouchbaseHealth {
|
||||
|
||||
private final DiagnosticsReport diagnostics;
|
||||
private final DiagnosticsResult diagnostics;
|
||||
|
||||
CouchbaseHealth(DiagnosticsReport diagnostics) {
|
||||
CouchbaseHealth(DiagnosticsResult diagnostics) {
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
void applyTo(Builder builder) {
|
||||
builder = isCouchbaseUp(this.diagnostics) ? builder.up() : builder.down();
|
||||
builder.withDetail("sdk", this.diagnostics.sdk());
|
||||
builder.withDetail("endpoints",
|
||||
this.diagnostics.endpoints().stream().map(this::describe).collect(Collectors.toList()));
|
||||
builder.withDetail("endpoints", this.diagnostics.endpoints().values().stream().flatMap(Collection::stream)
|
||||
.map(this::describe).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private boolean isCouchbaseUp(DiagnosticsReport diagnostics) {
|
||||
for (EndpointHealth health : diagnostics.endpoints()) {
|
||||
LifecycleState state = health.state();
|
||||
if (state != LifecycleState.CONNECTED && state != LifecycleState.IDLE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
private boolean isCouchbaseUp(DiagnosticsResult diagnostics) {
|
||||
return diagnostics.state() == ClusterState.ONLINE;
|
||||
}
|
||||
|
||||
private Map<String, Object> describe(EndpointHealth endpointHealth) {
|
||||
private Map<String, Object> describe(EndpointDiagnostics endpointHealth) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", endpointHealth.id());
|
||||
map.put("lastActivity", endpointHealth.lastActivity());
|
||||
map.put("local", endpointHealth.local().toString());
|
||||
map.put("remote", endpointHealth.remote().toString());
|
||||
map.put("local", endpointHealth.local());
|
||||
map.put("remote", endpointHealth.remote());
|
||||
map.put("state", endpointHealth.state());
|
||||
map.put("type", endpointHealth.type());
|
||||
return map;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import com.couchbase.client.core.message.internal.DiagnosticsReport;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
|
@ -48,7 +48,7 @@ public class CouchbaseHealthIndicator extends AbstractHealthIndicator {
|
|||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
DiagnosticsReport diagnostics = this.cluster.diagnostics();
|
||||
DiagnosticsResult diagnostics = this.cluster.diagnostics();
|
||||
new CouchbaseHealth(diagnostics).applyTo(builder);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import com.couchbase.client.core.message.internal.DiagnosticsReport;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class CouchbaseReactiveHealthIndicator extends AbstractReactiveHealthIndi
|
|||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
DiagnosticsReport diagnostics = this.cluster.diagnostics();
|
||||
DiagnosticsResult diagnostics = this.cluster.diagnostics();
|
||||
new CouchbaseHealth(diagnostics).applyTo(builder);
|
||||
return Mono.just(builder.build());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,15 +16,16 @@
|
|||
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.core.message.internal.DiagnosticsReport;
|
||||
import com.couchbase.client.core.message.internal.EndpointHealth;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
import com.couchbase.client.core.endpoint.EndpointState;
|
||||
import com.couchbase.client.core.service.ServiceType;
|
||||
import com.couchbase.client.core.state.LifecycleState;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -49,9 +50,11 @@ class CouchbaseHealthIndicatorTests {
|
|||
void couchbaseClusterIsUp() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
|
||||
List<EndpointHealth> endpoints = Arrays.asList(new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTED,
|
||||
new InetSocketAddress(0), new InetSocketAddress(0), 1234, "endpoint-1"));
|
||||
DiagnosticsReport diagnostics = new DiagnosticsReport(endpoints, "test-sdk", "test-id", null);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, "127.0.0.1",
|
||||
"127.0.0.1", Optional.empty(), Optional.of(1234L), Optional.of("endpoint-1"))));
|
||||
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
@ -66,12 +69,13 @@ class CouchbaseHealthIndicatorTests {
|
|||
void couchbaseClusterIsDown() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
|
||||
List<EndpointHealth> endpoints = Arrays.asList(
|
||||
new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTED, new InetSocketAddress(0),
|
||||
new InetSocketAddress(0), 1234, "endpoint-1"),
|
||||
new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTING, new InetSocketAddress(0),
|
||||
new InetSocketAddress(0), 1234, "endpoint-2"));
|
||||
DiagnosticsReport diagnostics = new DiagnosticsReport(endpoints, "test-sdk", "test-id", null);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Arrays.asList(
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, "127.0.0.1", "127.0.0.1",
|
||||
Optional.empty(), Optional.of(1234L), Optional.of("endpoint-1")),
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, "127.0.0.1", "127.0.0.1",
|
||||
Optional.empty(), Optional.of(1234L), Optional.of("endpoint-2"))));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -15,16 +15,17 @@
|
|||
*/
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.core.message.internal.DiagnosticsReport;
|
||||
import com.couchbase.client.core.message.internal.EndpointHealth;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
import com.couchbase.client.core.endpoint.EndpointState;
|
||||
import com.couchbase.client.core.service.ServiceType;
|
||||
import com.couchbase.client.core.state.LifecycleState;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -46,9 +47,10 @@ class CouchbaseReactiveHealthIndicatorTests {
|
|||
void couchbaseClusterIsUp() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
|
||||
List<EndpointHealth> endpoints = Arrays.asList(new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTED,
|
||||
new InetSocketAddress(0), new InetSocketAddress(0), 1234, "endpoint-1"));
|
||||
DiagnosticsReport diagnostics = new DiagnosticsReport(endpoints, "test-sdk", "test-id", null);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, "127.0.0.1",
|
||||
"127.0.0.1", Optional.empty(), Optional.of(1234L), Optional.of("endpoint-1"))));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
@ -63,12 +65,13 @@ class CouchbaseReactiveHealthIndicatorTests {
|
|||
void couchbaseClusterIsDown() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
|
||||
List<EndpointHealth> endpoints = Arrays.asList(
|
||||
new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTED, new InetSocketAddress(0),
|
||||
new InetSocketAddress(0), 1234, "endpoint-1"),
|
||||
new EndpointHealth(ServiceType.BINARY, LifecycleState.CONNECTING, new InetSocketAddress(0),
|
||||
new InetSocketAddress(0), 1234, "endpoint-2"));
|
||||
DiagnosticsReport diagnostics = new DiagnosticsReport(endpoints, "test-sdk", "test-id", null);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Arrays.asList(
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, "127.0.0.1", "127.0.0.1",
|
||||
Optional.empty(), Optional.of(1234L), Optional.of("endpoint-1")),
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, "127.0.0.1", "127.0.0.1",
|
||||
Optional.empty(), Optional.of(1234L), Optional.of("endpoint-2"))));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
|
|
|
@ -17,7 +17,6 @@ dependencies {
|
|||
optional(platform(project(":spring-boot-project:spring-boot-dependencies")))
|
||||
optional("com.atomikos:transactions-jdbc")
|
||||
optional("com.atomikos:transactions-jta")
|
||||
optional("com.couchbase.client:couchbase-spring-cache")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
|
||||
|
@ -181,7 +180,6 @@ dependencies {
|
|||
testImplementation("org.springframework.kafka:spring-kafka-test")
|
||||
testImplementation("org.springframework.security:spring-security-test")
|
||||
testImplementation("org.testcontainers:cassandra")
|
||||
testImplementation("org.testcontainers:couchbase")
|
||||
testImplementation("org.testcontainers:elasticsearch")
|
||||
testImplementation("org.testcontainers:junit-jupiter")
|
||||
testImplementation("org.testcontainers:testcontainers")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,23 +16,23 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.cache;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.spring.cache.CacheBuilder;
|
||||
import com.couchbase.client.spring.cache.CouchbaseCacheManager;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cache.CacheProperties.Couchbase;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Couchbase cache configuration.
|
||||
|
@ -41,22 +41,28 @@ import org.springframework.util.StringUtils;
|
|||
* @since 1.4.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Bucket.class, CouchbaseCacheManager.class })
|
||||
@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class })
|
||||
@ConditionalOnMissingBean(CacheManager.class)
|
||||
@ConditionalOnSingleCandidate(Bucket.class)
|
||||
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
|
||||
@Conditional(CacheCondition.class)
|
||||
public class CouchbaseCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
public CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
|
||||
Bucket bucket) {
|
||||
CouchbaseClientFactory clientFactory) {
|
||||
List<String> cacheNames = cacheProperties.getCacheNames();
|
||||
CacheBuilder builder = CacheBuilder.newInstance(bucket);
|
||||
CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory);
|
||||
Couchbase couchbase = cacheProperties.getCouchbase();
|
||||
PropertyMapper.get().from(couchbase::getExpiration).whenNonNull().asInt(Duration::getSeconds)
|
||||
.to(builder::withExpiration);
|
||||
String[] names = StringUtils.toStringArray(cacheNames);
|
||||
CouchbaseCacheManager cacheManager = new CouchbaseCacheManager(builder, names);
|
||||
org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration config = org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
|
||||
.defaultCacheConfig();
|
||||
if (couchbase.getExpiration() != null) {
|
||||
config = config.entryExpiry(couchbase.getExpiration());
|
||||
}
|
||||
builder.cacheDefaults(config);
|
||||
if (!ObjectUtils.isEmpty(cacheNames)) {
|
||||
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
|
||||
}
|
||||
CouchbaseCacheManager cacheManager = builder.build();
|
||||
return customizers.customize(cacheManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,24 +16,23 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
|
||||
/**
|
||||
* Callback interface that can be implemented by beans wishing to customize the
|
||||
* {@link CouchbaseEnvironment} via a {@link DefaultCouchbaseEnvironment.Builder} whilst
|
||||
* retaining default auto-configuration.
|
||||
* {@link ClusterEnvironment} via a {@link ClusterEnvironment.Builder} whilst retaining
|
||||
* default auto-configuration.whilst retaining default auto-configuration.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface CouchbaseEnvironmentBuilderCustomizer {
|
||||
public interface ClusterEnvironmentBuilderCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the {@link DefaultCouchbaseEnvironment.Builder}.
|
||||
* Customize the {@link ClusterEnvironment.Builder}.
|
||||
* @param builder the builder to customize
|
||||
*/
|
||||
void customize(DefaultCouchbaseEnvironment.Builder builder);
|
||||
void customize(ClusterEnvironment.Builder builder);
|
||||
|
||||
}
|
|
@ -16,28 +16,30 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import com.couchbase.client.core.env.KeyValueServiceConfig;
|
||||
import com.couchbase.client.core.env.QueryServiceConfig;
|
||||
import com.couchbase.client.core.env.ViewServiceConfig;
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import java.net.URL;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import com.couchbase.client.core.env.IoConfig;
|
||||
import com.couchbase.client.core.env.SecurityConfig;
|
||||
import com.couchbase.client.core.env.TimeoutConfig;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.CouchbaseBucket;
|
||||
import com.couchbase.client.java.CouchbaseCluster;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment.Builder;
|
||||
import com.couchbase.client.java.ClusterOptions;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment.Builder;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
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.couchbase.CouchbaseProperties.Endpoints;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts;
|
||||
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.context.annotation.DependsOn;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Couchbase.
|
||||
|
@ -48,106 +50,62 @@ import org.springframework.context.annotation.DependsOn;
|
|||
* @since 1.4.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ CouchbaseBucket.class, Cluster.class })
|
||||
@Conditional(OnBootstrapHostsCondition.class)
|
||||
@ConditionalOnClass(Cluster.class)
|
||||
@ConditionalOnProperty("spring.couchbase.connection-string")
|
||||
@EnableConfigurationProperties(CouchbaseProperties.class)
|
||||
public class CouchbaseAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(CouchbaseEnvironment.class)
|
||||
public DefaultCouchbaseEnvironment couchbaseEnvironment(CouchbaseProperties properties,
|
||||
ObjectProvider<CouchbaseEnvironmentBuilderCustomizer> customizers) {
|
||||
@ConditionalOnMissingBean
|
||||
public ClusterEnvironment couchbaseClusterEnvironment(CouchbaseProperties properties,
|
||||
ObjectProvider<ClusterEnvironmentBuilderCustomizer> customizers) {
|
||||
Builder builder = initializeEnvironmentBuilder(properties);
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Cluster.class)
|
||||
public CouchbaseCluster couchbaseCluster(CouchbaseProperties properties,
|
||||
CouchbaseEnvironment couchbaseEnvironment) {
|
||||
CouchbaseCluster couchbaseCluster = CouchbaseCluster.create(couchbaseEnvironment,
|
||||
properties.getBootstrapHosts());
|
||||
if (isRoleBasedAccessControlEnabled(properties)) {
|
||||
return couchbaseCluster.authenticate(properties.getUsername(), properties.getPassword());
|
||||
}
|
||||
return couchbaseCluster;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Bean(destroyMethod = "disconnect")
|
||||
@ConditionalOnMissingBean
|
||||
@DependsOn("couchbaseClient")
|
||||
public ClusterInfo couchbaseClusterInfo(CouchbaseProperties properties, Cluster couchbaseCluster) {
|
||||
if (isRoleBasedAccessControlEnabled(properties)) {
|
||||
return couchbaseCluster.clusterManager().info();
|
||||
}
|
||||
return couchbaseCluster.clusterManager(properties.getBucket().getName(), properties.getBucket().getPassword())
|
||||
.info();
|
||||
public Cluster couchbaseCluster(CouchbaseProperties properties, ClusterEnvironment couchbaseClusterEnvironment) {
|
||||
ClusterOptions options = ClusterOptions.clusterOptions(properties.getUsername(), properties.getPassword())
|
||||
.environment(couchbaseClusterEnvironment);
|
||||
return Cluster.connect(properties.getConnectionString(), options);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Bucket couchbaseClient(CouchbaseProperties properties, Cluster couchbaseCluster) {
|
||||
if (isRoleBasedAccessControlEnabled(properties)) {
|
||||
return couchbaseCluster.openBucket(properties.getBucket().getName());
|
||||
}
|
||||
return couchbaseCluster.openBucket(properties.getBucket().getName(), properties.getBucket().getPassword());
|
||||
}
|
||||
|
||||
private boolean isRoleBasedAccessControlEnabled(CouchbaseProperties properties) {
|
||||
return properties.getUsername() != null && properties.getPassword() != null;
|
||||
}
|
||||
|
||||
private DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder(CouchbaseProperties properties) {
|
||||
CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints();
|
||||
CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts();
|
||||
CouchbaseProperties.Bootstrap bootstrap = properties.getEnv().getBootstrap();
|
||||
DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment.builder();
|
||||
if (bootstrap.getHttpDirectPort() != null) {
|
||||
builder.bootstrapHttpDirectPort(bootstrap.getHttpDirectPort());
|
||||
}
|
||||
if (bootstrap.getHttpSslPort() != null) {
|
||||
builder.bootstrapHttpSslPort(bootstrap.getHttpSslPort());
|
||||
}
|
||||
if (timeouts.getConnect() != null) {
|
||||
builder = builder.connectTimeout(timeouts.getConnect().toMillis());
|
||||
}
|
||||
builder = builder.keyValueServiceConfig(KeyValueServiceConfig.create(endpoints.getKeyValue()));
|
||||
if (timeouts.getKeyValue() != null) {
|
||||
builder = builder.kvTimeout(timeouts.getKeyValue().toMillis());
|
||||
}
|
||||
if (timeouts.getQuery() != null) {
|
||||
builder = builder.queryTimeout(timeouts.getQuery().toMillis());
|
||||
builder = builder.queryServiceConfig(getQueryServiceConfig(endpoints));
|
||||
builder = builder.viewServiceConfig(getViewServiceConfig(endpoints));
|
||||
}
|
||||
if (timeouts.getSocketConnect() != null) {
|
||||
builder = builder.socketConnectTimeout((int) timeouts.getSocketConnect().toMillis());
|
||||
}
|
||||
if (timeouts.getView() != null) {
|
||||
builder = builder.viewTimeout(timeouts.getView().toMillis());
|
||||
}
|
||||
CouchbaseProperties.Ssl ssl = properties.getEnv().getSsl();
|
||||
if (ssl.getEnabled()) {
|
||||
builder = builder.sslEnabled(true);
|
||||
if (ssl.getKeyStore() != null) {
|
||||
builder = builder.sslKeystoreFile(ssl.getKeyStore());
|
||||
}
|
||||
if (ssl.getKeyStorePassword() != null) {
|
||||
builder = builder.sslKeystorePassword(ssl.getKeyStorePassword());
|
||||
}
|
||||
private ClusterEnvironment.Builder initializeEnvironmentBuilder(CouchbaseProperties properties) {
|
||||
ClusterEnvironment.Builder builder = ClusterEnvironment.builder();
|
||||
Timeouts timeouts = properties.getEnv().getTimeouts();
|
||||
builder.timeoutConfig(TimeoutConfig.kvTimeout(timeouts.getKeyValue()).queryTimeout(timeouts.getQuery())
|
||||
.viewTimeout(timeouts.getView()).connectTimeout(timeouts.getConnect()));
|
||||
CouchbaseProperties.Io io = properties.getEnv().getIo();
|
||||
builder.ioConfig(IoConfig.maxHttpConnections(io.getMaxEndpoints()).numKvConnections(io.getMinEndpoints())
|
||||
.idleHttpConnectionTimeout(io.getIdleHttpConnectionTimeout()));
|
||||
if (properties.getEnv().getSsl().getEnabled()) {
|
||||
builder.securityConfig(SecurityConfig.enableTls(true)
|
||||
.trustManagerFactory(getTrustManagerFactory(properties.getEnv().getSsl())));
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private QueryServiceConfig getQueryServiceConfig(Endpoints endpoints) {
|
||||
return QueryServiceConfig.create(endpoints.getQueryservice().getMinEndpoints(),
|
||||
endpoints.getQueryservice().getMaxEndpoints());
|
||||
private TrustManagerFactory getTrustManagerFactory(CouchbaseProperties.Ssl ssl) {
|
||||
String resource = ssl.getKeyStore();
|
||||
try {
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory
|
||||
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
KeyStore keyStore = loadKeyStore(resource, ssl.getKeyStorePassword());
|
||||
trustManagerFactory.init(keyStore);
|
||||
return trustManagerFactory;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not load Couchbase key store '" + resource + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private ViewServiceConfig getViewServiceConfig(Endpoints endpoints) {
|
||||
return ViewServiceConfig.create(endpoints.getViewservice().getMinEndpoints(),
|
||||
endpoints.getViewservice().getMaxEndpoints());
|
||||
private KeyStore loadKeyStore(String resource, String keyStorePassword) throws Exception {
|
||||
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
URL url = ResourceUtils.getURL(resource);
|
||||
store.load(url.openStream(), (keyStorePassword != null) ? keyStorePassword.toCharArray() : null);
|
||||
return store;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -29,36 +28,35 @@ import org.springframework.util.StringUtils;
|
|||
* @author Stephane Nicoll
|
||||
* @author Yulin Qin
|
||||
* @author Brian Clozel
|
||||
* @author Michael Nitschinger
|
||||
* @since 1.4.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.couchbase")
|
||||
public class CouchbaseProperties {
|
||||
|
||||
/**
|
||||
* Couchbase nodes (host or IP address) to bootstrap from.
|
||||
* Connection string used to locate the Couchbase cluster.
|
||||
*/
|
||||
private List<String> bootstrapHosts;
|
||||
private String connectionString;
|
||||
|
||||
/**
|
||||
* Cluster username when using role based access.
|
||||
* Cluster username.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Cluster password when using role based access.
|
||||
* Cluster password.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
private final Bucket bucket = new Bucket();
|
||||
|
||||
private final Env env = new Env();
|
||||
|
||||
public List<String> getBootstrapHosts() {
|
||||
return this.bootstrapHosts;
|
||||
public String getConnectionString() {
|
||||
return this.connectionString;
|
||||
}
|
||||
|
||||
public void setBootstrapHosts(List<String> bootstrapHosts) {
|
||||
this.bootstrapHosts = bootstrapHosts;
|
||||
public void setConnectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
|
@ -77,60 +75,20 @@ public class CouchbaseProperties {
|
|||
this.password = password;
|
||||
}
|
||||
|
||||
public Bucket getBucket() {
|
||||
return this.bucket;
|
||||
}
|
||||
|
||||
public Env getEnv() {
|
||||
return this.env;
|
||||
}
|
||||
|
||||
public static class Bucket {
|
||||
|
||||
/**
|
||||
* Name of the bucket to connect to.
|
||||
*/
|
||||
private String name = "default";
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Env {
|
||||
|
||||
private final Bootstrap bootstrap = new Bootstrap();
|
||||
|
||||
private final Endpoints endpoints = new Endpoints();
|
||||
private final Io io = new Io();
|
||||
|
||||
private final Ssl ssl = new Ssl();
|
||||
|
||||
private final Timeouts timeouts = new Timeouts();
|
||||
|
||||
public Bootstrap getBootstrap() {
|
||||
return this.bootstrap;
|
||||
}
|
||||
|
||||
public Endpoints getEndpoints() {
|
||||
return this.endpoints;
|
||||
public Io getIo() {
|
||||
return this.io;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
|
@ -143,67 +101,46 @@ public class CouchbaseProperties {
|
|||
|
||||
}
|
||||
|
||||
public static class Endpoints {
|
||||
public static class Io {
|
||||
|
||||
/**
|
||||
* Number of sockets per node against the key/value service.
|
||||
* Minimum number of sockets per node.
|
||||
*/
|
||||
private int keyValue = 1;
|
||||
private int minEndpoints = 1;
|
||||
|
||||
/**
|
||||
* Query (N1QL) service configuration.
|
||||
* Maximum number of sockets per node.
|
||||
*/
|
||||
private final CouchbaseService queryservice = new CouchbaseService();
|
||||
private int maxEndpoints = 12;
|
||||
|
||||
/**
|
||||
* View service configuration.
|
||||
* Length of time an HTTP connection may remain idle before it is closed and
|
||||
* removed from the pool.
|
||||
*/
|
||||
private final CouchbaseService viewservice = new CouchbaseService();
|
||||
private Duration idleHttpConnectionTimeout = Duration.ofSeconds(30);
|
||||
|
||||
public int getKeyValue() {
|
||||
return this.keyValue;
|
||||
public int getMinEndpoints() {
|
||||
return this.minEndpoints;
|
||||
}
|
||||
|
||||
public void setKeyValue(int keyValue) {
|
||||
this.keyValue = keyValue;
|
||||
public void setMinEndpoints(int minEndpoints) {
|
||||
this.minEndpoints = minEndpoints;
|
||||
}
|
||||
|
||||
public CouchbaseService getQueryservice() {
|
||||
return this.queryservice;
|
||||
public int getMaxEndpoints() {
|
||||
return this.maxEndpoints;
|
||||
}
|
||||
|
||||
public CouchbaseService getViewservice() {
|
||||
return this.viewservice;
|
||||
public void setMaxEndpoints(int maxEndpoints) {
|
||||
this.maxEndpoints = maxEndpoints;
|
||||
}
|
||||
|
||||
public static class CouchbaseService {
|
||||
|
||||
/**
|
||||
* Minimum number of sockets per node.
|
||||
*/
|
||||
private int minEndpoints = 1;
|
||||
|
||||
/**
|
||||
* Maximum number of sockets per node.
|
||||
*/
|
||||
private int maxEndpoints = 1;
|
||||
|
||||
public int getMinEndpoints() {
|
||||
return this.minEndpoints;
|
||||
}
|
||||
|
||||
public void setMinEndpoints(int minEndpoints) {
|
||||
this.minEndpoints = minEndpoints;
|
||||
}
|
||||
|
||||
public int getMaxEndpoints() {
|
||||
return this.maxEndpoints;
|
||||
}
|
||||
|
||||
public void setMaxEndpoints(int maxEndpoints) {
|
||||
this.maxEndpoints = maxEndpoints;
|
||||
}
|
||||
public Duration getIdleHttpConnectionTimeout() {
|
||||
return this.idleHttpConnectionTimeout;
|
||||
}
|
||||
|
||||
public void setIdleHttpConnectionTimeout(Duration idleHttpConnectionTimeout) {
|
||||
this.idleHttpConnectionTimeout = idleHttpConnectionTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -255,29 +192,24 @@ public class CouchbaseProperties {
|
|||
public static class Timeouts {
|
||||
|
||||
/**
|
||||
* Bucket connections timeouts.
|
||||
* Bucket connect timeouts.
|
||||
*/
|
||||
private Duration connect = Duration.ofMillis(5000);
|
||||
private Duration connect = Duration.ofSeconds(10);
|
||||
|
||||
/**
|
||||
* Blocking operations performed on a specific key timeout.
|
||||
* operations performed on a specific key timeout.
|
||||
*/
|
||||
private Duration keyValue = Duration.ofMillis(2500);
|
||||
|
||||
/**
|
||||
* N1QL query operations timeout.
|
||||
*/
|
||||
private Duration query = Duration.ofMillis(7500);
|
||||
|
||||
/**
|
||||
* Socket connect connections timeout.
|
||||
*/
|
||||
private Duration socketConnect = Duration.ofMillis(1000);
|
||||
private Duration query = Duration.ofSeconds(75);
|
||||
|
||||
/**
|
||||
* Regular and geospatial view operations timeout.
|
||||
*/
|
||||
private Duration view = Duration.ofMillis(7500);
|
||||
private Duration view = Duration.ofSeconds(75);
|
||||
|
||||
public Duration getConnect() {
|
||||
return this.connect;
|
||||
|
@ -303,14 +235,6 @@ public class CouchbaseProperties {
|
|||
this.query = query;
|
||||
}
|
||||
|
||||
public Duration getSocketConnect() {
|
||||
return this.socketConnect;
|
||||
}
|
||||
|
||||
public void setSocketConnect(Duration socketConnect) {
|
||||
this.socketConnect = socketConnect;
|
||||
}
|
||||
|
||||
public Duration getView() {
|
||||
return this.view;
|
||||
}
|
||||
|
@ -321,34 +245,4 @@ public class CouchbaseProperties {
|
|||
|
||||
}
|
||||
|
||||
public static class Bootstrap {
|
||||
|
||||
/**
|
||||
* Port for the HTTP bootstrap.
|
||||
*/
|
||||
private Integer httpDirectPort;
|
||||
|
||||
/**
|
||||
* Port for the HTTPS bootstrap.
|
||||
*/
|
||||
private Integer httpSslPort;
|
||||
|
||||
public Integer getHttpDirectPort() {
|
||||
return this.httpDirectPort;
|
||||
}
|
||||
|
||||
public void setHttpDirectPort(Integer httpDirectPort) {
|
||||
this.httpDirectPort = httpDirectPort;
|
||||
}
|
||||
|
||||
public Integer getHttpSslPort() {
|
||||
return this.httpSslPort;
|
||||
}
|
||||
|
||||
public void setHttpSslPort(Integer httpSslPort) {
|
||||
this.httpSslPort = httpSslPort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.Cluster;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.SimpleCouchbaseClientFactory;
|
||||
|
||||
/**
|
||||
* Configuration for a {@link CouchbaseClientFactory}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnSingleCandidate(Cluster.class)
|
||||
@ConditionalOnProperty("spring.data.couchbase.bucket-name")
|
||||
class CouchbaseClientFactoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
CouchbaseClientFactory couchbaseClientFactory(Cluster cluster, CouchbaseDataProperties properties) {
|
||||
return new SimpleCouchbaseClientFactory(cluster, properties.getBucketName(), properties.getScopeName());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
|
||||
/**
|
||||
* Configuration for Couchbase-related beans that depend on a
|
||||
* {@link CouchbaseClientFactory}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
|
||||
class CouchbaseClientFactoryDependentConfiguration {
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE)
|
||||
CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
|
||||
MappingCouchbaseConverter mappingCouchbaseConverter) {
|
||||
return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
|
||||
RepositoryOperationsMapping couchbaseRepositoryOperationsMapping(CouchbaseTemplate couchbaseTemplate) {
|
||||
return new RepositoryOperationsMapping(couchbaseTemplate);
|
||||
}
|
||||
|
||||
}
|
|
@ -44,7 +44,8 @@ import org.springframework.data.couchbase.repository.CouchbaseRepository;
|
|||
@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class })
|
||||
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, ValidationAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(CouchbaseDataProperties.class)
|
||||
@Import(CouchbaseDataConfiguration.class)
|
||||
@Import({ CouchbaseDataConfiguration.class, CouchbaseClientFactoryConfiguration.class,
|
||||
CouchbaseClientFactoryDependentConfiguration.class })
|
||||
public class CouchbaseDataAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
|
|
@ -18,28 +18,20 @@ package org.springframework.boot.autoconfigure.data.couchbase;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScanner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
|
||||
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||
|
||||
/**
|
||||
|
@ -50,8 +42,8 @@ import org.springframework.data.mapping.model.FieldNamingStrategy;
|
|||
@Configuration(proxyBeanMethods = false)
|
||||
class CouchbaseDataConfiguration {
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_MAPPING_CONVERTER)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_MAPPING_CONVERTER)
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
MappingCouchbaseConverter couchbaseMappingConverter(CouchbaseDataProperties properties,
|
||||
CouchbaseMappingContext couchbaseMappingContext, CouchbaseCustomConversions couchbaseCustomConversions) {
|
||||
MappingCouchbaseConverter converter = new MappingCouchbaseConverter(couchbaseMappingContext,
|
||||
|
@ -60,8 +52,8 @@ class CouchbaseDataConfiguration {
|
|||
return converter;
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_TRANSLATION_SERVICE)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TRANSLATION_SERVICE)
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TranslationService couchbaseTranslationService() {
|
||||
return new JacksonTranslationService();
|
||||
}
|
||||
|
@ -80,6 +72,7 @@ class CouchbaseDataConfiguration {
|
|||
mappingContext
|
||||
.setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(fieldNamingStrategy));
|
||||
}
|
||||
mappingContext.setAutoIndexCreation(properties.isAutoIndex());
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
|
@ -89,31 +82,4 @@ class CouchbaseDataConfiguration {
|
|||
return new CouchbaseCustomConversions(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_INDEX_MANAGER)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_INDEX_MANAGER)
|
||||
IndexManager indexManager(CouchbaseDataProperties properties) {
|
||||
if (properties.isAutoIndex()) {
|
||||
return new IndexManager(true, true, true);
|
||||
}
|
||||
return new IndexManager(false, false, false);
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnBean({ ClusterInfo.class, Bucket.class })
|
||||
CouchbaseTemplate couchbaseTemplate(CouchbaseDataProperties properties, ClusterInfo clusterInfo, Bucket bucket,
|
||||
MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService translationService) {
|
||||
CouchbaseTemplate template = new CouchbaseTemplate(clusterInfo, bucket, mappingCouchbaseConverter,
|
||||
translationService);
|
||||
template.setDefaultConsistency(properties.getConsistency());
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
|
||||
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)
|
||||
@ConditionalOnSingleCandidate(CouchbaseTemplate.class)
|
||||
RepositoryOperationsMapping repositoryOperationsMapping(CouchbaseTemplate couchbaseTemplate) {
|
||||
return new RepositoryOperationsMapping(couchbaseTemplate);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
|
||||
/**
|
||||
* Configuration properties for Spring Data Couchbase.
|
||||
|
@ -35,9 +34,14 @@ public class CouchbaseDataProperties {
|
|||
private boolean autoIndex;
|
||||
|
||||
/**
|
||||
* Consistency to apply by default on generated queries.
|
||||
* Name of the bucket to connect to.
|
||||
*/
|
||||
private Consistency consistency = Consistency.READ_YOUR_OWN_WRITES;
|
||||
private String bucketName;
|
||||
|
||||
/**
|
||||
* Name of the scope used for all collection access.
|
||||
*/
|
||||
private String scopeName;
|
||||
|
||||
/**
|
||||
* Fully qualified name of the FieldNamingStrategy to use.
|
||||
|
@ -58,12 +62,20 @@ public class CouchbaseDataProperties {
|
|||
this.autoIndex = autoIndex;
|
||||
}
|
||||
|
||||
public Consistency getConsistency() {
|
||||
return this.consistency;
|
||||
public String getBucketName() {
|
||||
return this.bucketName;
|
||||
}
|
||||
|
||||
public void setConsistency(Consistency consistency) {
|
||||
this.consistency = consistency;
|
||||
public void setBucketName(String bucketName) {
|
||||
this.bucketName = bucketName;
|
||||
}
|
||||
|
||||
public String getScopeName() {
|
||||
return this.scopeName;
|
||||
}
|
||||
|
||||
public void setScopeName(String scopeName) {
|
||||
this.scopeName = scopeName;
|
||||
}
|
||||
|
||||
public Class<?> getFieldNamingStrategy() {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
|
@ -34,7 +34,7 @@ import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Bucket.class, ReactiveCouchbaseRepository.class, Flux.class })
|
||||
@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class })
|
||||
@AutoConfigureAfter(CouchbaseDataAutoConfiguration.class)
|
||||
@Import(CouchbaseReactiveDataConfiguration.class)
|
||||
public class CouchbaseReactiveDataAutoConfiguration {
|
||||
|
|
|
@ -16,18 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
|
||||
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
|
||||
|
||||
/**
|
||||
|
@ -36,24 +32,20 @@ import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOp
|
|||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
|
||||
class CouchbaseReactiveDataConfiguration {
|
||||
|
||||
@Bean(name = BeanNames.RXJAVA1_COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnMissingBean(name = BeanNames.RXJAVA1_COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnBean({ ClusterInfo.class, Bucket.class })
|
||||
RxJavaCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseDataProperties properties, ClusterInfo clusterInfo,
|
||||
Bucket bucket, MappingCouchbaseConverter mappingCouchbaseConverter, TranslationService translationService) {
|
||||
RxJavaCouchbaseTemplate template = new RxJavaCouchbaseTemplate(clusterInfo, bucket, mappingCouchbaseConverter,
|
||||
translationService);
|
||||
template.setDefaultConsistency(properties.getConsistency());
|
||||
return template;
|
||||
@Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)
|
||||
@ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)
|
||||
ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,
|
||||
MappingCouchbaseConverter mappingCouchbaseConverter) {
|
||||
return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);
|
||||
}
|
||||
|
||||
@Bean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING)
|
||||
@ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING)
|
||||
@ConditionalOnSingleCandidate(RxJavaCouchbaseTemplate.class)
|
||||
ReactiveRepositoryOperationsMapping reactiveRepositoryOperationsMapping(
|
||||
RxJavaCouchbaseTemplate reactiveCouchbaseTemplate) {
|
||||
ReactiveRepositoryOperationsMapping reactiveCouchbaseRepositoryOperationsMapping(
|
||||
ReactiveCouchbaseTemplate reactiveCouchbaseTemplate) {
|
||||
return new ReactiveRepositoryOperationsMapping(reactiveCouchbaseTemplate);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
|
@ -40,7 +40,7 @@ import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRe
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ Bucket.class, ReactiveCouchbaseRepository.class, Flux.class })
|
||||
@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class })
|
||||
@ConditionalOnRepositoryType(store = "couchbase", type = RepositoryType.REACTIVE)
|
||||
@ConditionalOnBean(ReactiveRepositoryOperationsMapping.class)
|
||||
@ConditionalOnMissingBean(ReactiveCouchbaseRepositoryFactoryBean.class)
|
||||
|
|
|
@ -328,10 +328,6 @@
|
|||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.data.couchbase.consistency",
|
||||
"defaultValue": "read-your-own-writes"
|
||||
},
|
||||
{
|
||||
"name": "spring.data.couchbase.repositories.type",
|
||||
"type": "org.springframework.boot.autoconfigure.data.RepositoryType",
|
||||
|
@ -1594,6 +1590,101 @@
|
|||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.bootstrap-hosts",
|
||||
"type": "java.util.List<java.lang.String>",
|
||||
"description": "Couchbase nodes (host or IP address) to bootstrap from.",
|
||||
"deprecation": {
|
||||
"replacement": "spring.couchbase.connection-string",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.bucket.name",
|
||||
"type": "java.lang.String",
|
||||
"description": "Name of the bucket to connect to.",
|
||||
"deprecation": {
|
||||
"reason": "A bucket is no longer auto-configured.",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.bucket.password",
|
||||
"type": "java.lang.String",
|
||||
"description": "Password of the bucket.",
|
||||
"deprecation": {
|
||||
"reason": "A bucket is no longer auto-configured.",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.bootstrap.http-direct-port",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Port for the HTTP bootstrap.",
|
||||
"deprecation": {
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.bootstrap.http-ssl-port",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Port for the HTTPS bootstrap.",
|
||||
"deprecation": {
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.key-value",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Number of sockets per node against the key/value service.",
|
||||
"deprecation": {
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.queryservice.max-endpoints",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Maximum number of sockets per node.",
|
||||
"deprecation": {
|
||||
"replacement": "spring.couchbase.env.io.max-endpoints",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.queryservice.min-endpoints",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Minimum number of sockets per node.",
|
||||
"deprecation": {
|
||||
"replacement": "spring.couchbase.env.io.min-endpoints",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.viewservice.max-endpoints",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Maximum number of sockets per node.",
|
||||
"deprecation": {
|
||||
"replacement": "spring.couchbase.env.io.max-endpoints",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.viewservice.min-endpoints",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "Minimum number of sockets per node.",
|
||||
"deprecation": {
|
||||
"replacement": "spring.couchbase.env.io.min-endpoints",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.timeouts.socket-connect",
|
||||
"type": "java.time.Duration",
|
||||
"description": "Socket connect connections timeout.",
|
||||
"deprecation": {
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.couchbase.env.endpoints.query",
|
||||
"type": "java.lang.Integer",
|
||||
|
@ -1655,6 +1746,14 @@
|
|||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.data.couchbase.consistency",
|
||||
"type": "org.springframework.data.couchbase.core.query.Consistency",
|
||||
"deprecation": {
|
||||
"replacement": "spring.data.cassandra.read-timeout",
|
||||
"level": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spring.data.neo4j.compiler",
|
||||
"type": "java.lang.String",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -21,7 +21,6 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.couchbase.client.spring.cache.CouchbaseCacheManager;
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
import org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;
|
||||
|
||||
|
@ -36,6 +35,7 @@ import org.springframework.cache.ehcache.EhCacheCacheManager;
|
|||
import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
|
@ -26,10 +26,6 @@ import javax.cache.configuration.MutableConfiguration;
|
|||
import javax.cache.expiry.CreatedExpiryPolicy;
|
||||
import javax.cache.expiry.Duration;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.bucket.BucketManager;
|
||||
import com.couchbase.client.spring.cache.CouchbaseCache;
|
||||
import com.couchbase.client.spring.cache.CouchbaseCacheManager;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.CaffeineSpec;
|
||||
import com.hazelcast.cache.HazelcastCachingProvider;
|
||||
|
@ -66,6 +62,9 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCache;
|
||||
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
|
@ -220,8 +219,7 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
|
|||
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
|
||||
Cache cache = cacheManager.getCache("foo");
|
||||
assertThat(cache).isInstanceOf(CouchbaseCache.class);
|
||||
assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(0);
|
||||
assertThat(((CouchbaseCache) cache).getNativeCache()).isEqualTo(context.getBean("bucket"));
|
||||
assertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -235,8 +233,7 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
|
|||
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
|
||||
Cache cache = cacheManager.getCache("foo");
|
||||
assertThat(cache).isInstanceOf(CouchbaseCache.class);
|
||||
assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(2);
|
||||
assertThat(((CouchbaseCache) cache).getNativeCache()).isEqualTo(context.getBean("bucket"));
|
||||
assertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(2);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -725,11 +722,8 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
|
|||
static class CouchbaseCacheConfiguration {
|
||||
|
||||
@Bean
|
||||
Bucket bucket() {
|
||||
BucketManager bucketManager = mock(BucketManager.class);
|
||||
Bucket bucket = mock(Bucket.class);
|
||||
given(bucket.bucketManager()).willReturn(bucketManager);
|
||||
return bucket;
|
||||
CouchbaseClientFactory couchbaseClientFactory() {
|
||||
return mock(CouchbaseClientFactory.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,31 +17,21 @@
|
|||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.ClusterState;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.bucket.BucketType;
|
||||
import com.couchbase.client.java.cluster.BucketSettings;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
import com.couchbase.client.java.cluster.DefaultBucketSettings;
|
||||
import com.couchbase.client.java.cluster.UserRole;
|
||||
import com.couchbase.client.java.cluster.UserSettings;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.manager.bucket.BucketSettings;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.couchbase.CouchbaseContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link CouchbaseAutoConfiguration}.
|
||||
|
@ -52,45 +42,29 @@ import static org.mockito.Mockito.mock;
|
|||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class CouchbaseAutoConfigurationIntegrationTests {
|
||||
|
||||
private static final String BUCKET_NAME = "cbbucket";
|
||||
|
||||
@Container
|
||||
static final CouchbaseContainer couchbase = new CouchbaseContainer().withClusterAdmin("spring", "password")
|
||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10))
|
||||
.withNewBucket(BucketSettings.create(BUCKET_NAME));
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class))
|
||||
.withPropertyValues("spring.couchbase.bootstrap-hosts=localhost",
|
||||
"spring.couchbase.env.bootstrap.http-direct-port:" + couchbase.getMappedPort(8091),
|
||||
.withPropertyValues("spring.couchbase.connection-string:localhost:" + couchbase.getMappedPort(11210),
|
||||
"spring.couchbase.username:spring", "spring.couchbase.password:password",
|
||||
"spring.couchbase.bucket.name:default");
|
||||
|
||||
@BeforeAll
|
||||
static void createBucket() {
|
||||
BucketSettings bucketSettings = DefaultBucketSettings.builder().enableFlush(true).name("default")
|
||||
.password("password").quota(100).replicas(0).type(BucketType.COUCHBASE).build();
|
||||
List<UserRole> userSettings = Collections.singletonList(new UserRole("admin"));
|
||||
couchbase.createBucket(bucketSettings,
|
||||
UserSettings.build().password(bucketSettings.password()).roles(userSettings), true);
|
||||
}
|
||||
"spring.couchbase.bucket.name:" + BUCKET_NAME);
|
||||
|
||||
@Test
|
||||
void defaultConfiguration() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CouchbaseEnvironment.class)
|
||||
.hasSingleBean(Cluster.class).hasSingleBean(ClusterInfo.class).hasSingleBean(Bucket.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomConfiguration {
|
||||
|
||||
@Bean
|
||||
Cluster myCustomCouchbaseCluster() {
|
||||
return mock(Cluster.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Bucket myCustomCouchbaseClient() {
|
||||
return mock(Bucket.class);
|
||||
}
|
||||
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(Cluster.class).hasSingleBean(ClusterEnvironment.class);
|
||||
Cluster cluster = context.getBean(Cluster.class);
|
||||
Bucket bucket = cluster.bucket(BUCKET_NAME);
|
||||
bucket.waitUntilReady(Duration.ofMinutes(5));
|
||||
DiagnosticsResult diagnostics = cluster.diagnostics();
|
||||
assertThat(diagnostics.state()).isEqualTo(ClusterState.ONLINE);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.couchbase.client.core.env.IoConfig;
|
||||
import com.couchbase.client.core.env.SecurityConfig;
|
||||
import com.couchbase.client.core.env.TimeoutConfig;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.env.CouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
|
@ -42,119 +45,91 @@ class CouchbaseAutoConfigurationTests {
|
|||
.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void bootstrapHostsIsRequired() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(CouchbaseEnvironment.class)
|
||||
void connectionStringIsRequired() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClusterEnvironment.class)
|
||||
.doesNotHaveBean(Cluster.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bootstrapHostsCreateEnvironmentAndCluster() {
|
||||
void connectionStringCreateEnvironmentAndCluster() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.withPropertyValues("spring.couchbase.bootstrap-hosts=localhost").run((context) -> {
|
||||
assertThat(context).hasSingleBean(CouchbaseEnvironment.class).hasSingleBean(Cluster.class);
|
||||
.withPropertyValues("spring.couchbase.connection-string=localhost").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ClusterEnvironment.class).hasSingleBean(Cluster.class);
|
||||
assertThat(context.getBean(Cluster.class))
|
||||
.isSameAs(context.getBean(CouchbaseTestConfiguration.class).couchbaseCluster());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeEnvEndpoints() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.kvServiceConfig().minEndpoints()).isEqualTo(2);
|
||||
assertThat(env.kvServiceConfig().maxEndpoints()).isEqualTo(2);
|
||||
assertThat(env.queryServiceConfig().minEndpoints()).isEqualTo(3);
|
||||
assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(5);
|
||||
assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(4);
|
||||
assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(6);
|
||||
}, "spring.couchbase.env.endpoints.key-value=2", "spring.couchbase.env.endpoints.queryservice.min-endpoints=3",
|
||||
"spring.couchbase.env.endpoints.queryservice.max-endpoints=5",
|
||||
"spring.couchbase.env.endpoints.viewservice.min-endpoints=4",
|
||||
"spring.couchbase.env.endpoints.viewservice.max-endpoints=6");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeEnvEndpointsUsesNewInfrastructure() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.queryServiceConfig().minEndpoints()).isEqualTo(3);
|
||||
assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(5);
|
||||
assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(4);
|
||||
assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(6);
|
||||
}, "spring.couchbase.env.endpoints.queryservice.min-endpoints=3",
|
||||
"spring.couchbase.env.endpoints.queryservice.max-endpoints=5",
|
||||
"spring.couchbase.env.endpoints.viewservice.min-endpoints=4",
|
||||
"spring.couchbase.env.endpoints.viewservice.max-endpoints=6");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeEnvEndpointsUsesNewInfrastructureWithOnlyMax() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.queryServiceConfig().minEndpoints()).isEqualTo(1);
|
||||
assertThat(env.queryServiceConfig().maxEndpoints()).isEqualTo(5);
|
||||
assertThat(env.viewServiceConfig().minEndpoints()).isEqualTo(1);
|
||||
assertThat(env.viewServiceConfig().maxEndpoints()).isEqualTo(6);
|
||||
}, "spring.couchbase.env.endpoints.queryservice.max-endpoints=5",
|
||||
"spring.couchbase.env.endpoints.viewservice.max-endpoints=6");
|
||||
void customizeEnvIo() {
|
||||
testClusterEnvironment((env) -> {
|
||||
IoConfig ioConfig = env.ioConfig();
|
||||
assertThat(ioConfig.numKvConnections()).isEqualTo(2);
|
||||
assertThat(ioConfig.maxHttpConnections()).isEqualTo(5);
|
||||
assertThat(ioConfig.idleHttpConnectionTimeout()).isEqualTo(Duration.ofSeconds(3));
|
||||
}, "spring.couchbase.env.io.min-endpoints=2", "spring.couchbase.env.io.max-endpoints=5",
|
||||
"spring.couchbase.env.io.idle-http-connection-timeout=3s");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeEnvTimeouts() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.connectTimeout()).isEqualTo(100);
|
||||
assertThat(env.kvTimeout()).isEqualTo(200);
|
||||
assertThat(env.queryTimeout()).isEqualTo(300);
|
||||
assertThat(env.socketConnectTimeout()).isEqualTo(400);
|
||||
assertThat(env.viewTimeout()).isEqualTo(500);
|
||||
}, "spring.couchbase.env.timeouts.connect=100", "spring.couchbase.env.timeouts.keyValue=200",
|
||||
"spring.couchbase.env.timeouts.query=300", "spring.couchbase.env.timeouts.socket-connect=400",
|
||||
"spring.couchbase.env.timeouts.view=500");
|
||||
testClusterEnvironment((env) -> {
|
||||
TimeoutConfig timeoutConfig = env.timeoutConfig();
|
||||
assertThat(timeoutConfig.connectTimeout()).isEqualTo(Duration.ofSeconds(1));
|
||||
assertThat(timeoutConfig.kvTimeout()).isEqualTo(Duration.ofMillis(500));
|
||||
assertThat(timeoutConfig.queryTimeout()).isEqualTo(Duration.ofSeconds(3));
|
||||
assertThat(timeoutConfig.viewTimeout()).isEqualTo(Duration.ofSeconds(4));
|
||||
}, "spring.couchbase.env.timeouts.connect=1s", "spring.couchbase.env.timeouts.key-value=500ms",
|
||||
"spring.couchbase.env.timeouts.query=3s", "spring.couchbase.env.timeouts.view=4s");
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableSslNoEnabledFlag() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.sslEnabled()).isTrue();
|
||||
assertThat(env.sslKeystoreFile()).isEqualTo("foo");
|
||||
assertThat(env.sslKeystorePassword()).isEqualTo("secret");
|
||||
}, "spring.couchbase.env.ssl.keyStore=foo", "spring.couchbase.env.ssl.keyStorePassword=secret");
|
||||
testClusterEnvironment((env) -> {
|
||||
SecurityConfig securityConfig = env.securityConfig();
|
||||
assertThat(securityConfig.tlsEnabled()).isTrue();
|
||||
assertThat(securityConfig.trustManagerFactory()).isNotNull();
|
||||
}, "spring.couchbase.env.ssl.keyStore=classpath:test.jks", "spring.couchbase.env.ssl.keyStorePassword=secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
void disableSslEvenWithKeyStore() {
|
||||
testCouchbaseEnv((env) -> {
|
||||
assertThat(env.sslEnabled()).isFalse();
|
||||
assertThat(env.sslKeystoreFile()).isNull();
|
||||
assertThat(env.sslKeystorePassword()).isNull();
|
||||
}, "spring.couchbase.env.ssl.enabled=false", "spring.couchbase.env.ssl.keyStore=foo",
|
||||
testClusterEnvironment((env) -> {
|
||||
SecurityConfig securityConfig = env.securityConfig();
|
||||
assertThat(securityConfig.tlsEnabled()).isFalse();
|
||||
assertThat(securityConfig.trustManagerFactory()).isNull();
|
||||
}, "spring.couchbase.env.ssl.enabled=false", "spring.couchbase.env.ssl.keyStore=classpath:test.jks",
|
||||
"spring.couchbase.env.ssl.keyStorePassword=secret");
|
||||
}
|
||||
|
||||
private void testCouchbaseEnv(Consumer<DefaultCouchbaseEnvironment> environmentConsumer, String... environment) {
|
||||
private void testClusterEnvironment(Consumer<ClusterEnvironment> environmentConsumer, String... environment) {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.withPropertyValues("spring.couchbase.bootstrap-hosts=localhost").withPropertyValues(environment)
|
||||
.run((context) -> environmentConsumer.accept(context.getBean(DefaultCouchbaseEnvironment.class)));
|
||||
.withPropertyValues("spring.couchbase.connection-string=localhost").withPropertyValues(environment)
|
||||
.run((context) -> environmentConsumer.accept(context.getBean(ClusterEnvironment.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeEnvWithCustomCouchbaseConfiguration() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(CouchbaseTestConfiguration.class,
|
||||
CouchbaseEnvironmentCustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.couchbase.bootstrap-hosts=localhost",
|
||||
ClusterEnvironmentCustomizerConfiguration.class)
|
||||
.withPropertyValues("spring.couchbase.connection-string=localhost",
|
||||
"spring.couchbase.env.timeouts.connect=100")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(DefaultCouchbaseEnvironment.class);
|
||||
DefaultCouchbaseEnvironment env = context.getBean(DefaultCouchbaseEnvironment.class);
|
||||
assertThat(env.socketConnectTimeout()).isEqualTo(5000);
|
||||
assertThat(env.connectTimeout()).isEqualTo(2000);
|
||||
assertThat(context).hasSingleBean(ClusterEnvironment.class);
|
||||
ClusterEnvironment env = context.getBean(ClusterEnvironment.class);
|
||||
assertThat(env.timeoutConfig().kvTimeout()).isEqualTo(Duration.ofSeconds(5));
|
||||
assertThat(env.timeoutConfig().connectTimeout()).isEqualTo(Duration.ofSeconds(2));
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CouchbaseEnvironmentCustomizerConfiguration {
|
||||
static class ClusterEnvironmentCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
CouchbaseEnvironmentBuilderCustomizer couchbaseEnvironmentBuilderCustomizer() {
|
||||
return (builder) -> builder.socketConnectTimeout(5000).connectTimeout(2000);
|
||||
ClusterEnvironmentBuilderCustomizer clusterEnvironmentBuilderCustomizer() {
|
||||
return (builder) -> builder.timeoutConfig().kvTimeout(Duration.ofSeconds(5))
|
||||
.connectTimeout(Duration.ofSeconds(2));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,504 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://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.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.couchbase.client.core.env.SeedNode;
|
||||
import com.couchbase.client.core.env.TimeoutConfig;
|
||||
import com.couchbase.client.core.util.UrlQueryStringBuilder;
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.ClusterOptions;
|
||||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.manager.bucket.BucketSettings;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
|
||||
import com.github.dockerjava.api.command.InspectContainerResponse;
|
||||
import com.github.dockerjava.core.command.ExecStartResultCallback;
|
||||
import org.apache.commons.compress.utils.Sets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.testcontainers.containers.SocatContainer;
|
||||
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
|
||||
import org.testcontainers.images.builder.Transferable;
|
||||
import org.testcontainers.shaded.org.apache.commons.io.IOUtils;
|
||||
import org.testcontainers.utility.ThrowingFunction;
|
||||
|
||||
import static java.net.HttpURLConnection.HTTP_OK;
|
||||
import static org.testcontainers.shaded.org.apache.commons.codec.binary.Base64.encodeBase64String;
|
||||
|
||||
/**
|
||||
* Temporary copy of TestContainers's Couchbase support until it works against Couchbase
|
||||
* SDK v3.
|
||||
*/
|
||||
class CouchbaseContainer extends GenericContainer<CouchbaseContainer> {
|
||||
|
||||
public static final String VERSION = "5.5.1";
|
||||
|
||||
public static final String DOCKER_IMAGE_NAME = "couchbase/server:";
|
||||
|
||||
public static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
public static final String STATIC_CONFIG = "/opt/couchbase/etc/couchbase/static_config";
|
||||
|
||||
public static final String CAPI_CONFIG = "/opt/couchbase/etc/couchdb/default.d/capi.ini";
|
||||
|
||||
private static final int REQUIRED_DEFAULT_PASSWORD_LENGTH = 6;
|
||||
|
||||
private String memoryQuota = "300";
|
||||
|
||||
private String indexMemoryQuota = "300";
|
||||
|
||||
private String clusterUsername = "Administrator";
|
||||
|
||||
private String clusterPassword = "password";
|
||||
|
||||
private boolean keyValue = true;
|
||||
|
||||
private boolean query = true;
|
||||
|
||||
private boolean index = true;
|
||||
|
||||
private boolean primaryIndex = false;
|
||||
|
||||
private boolean fts = false;
|
||||
|
||||
private ClusterEnvironment couchbaseEnvironment;
|
||||
|
||||
private Cluster couchbaseCluster;
|
||||
|
||||
private final List<BucketAndUserSettings> newBuckets = new ArrayList<>();
|
||||
|
||||
private String urlBase;
|
||||
|
||||
private SocatContainer proxy;
|
||||
|
||||
CouchbaseContainer() {
|
||||
this(DOCKER_IMAGE_NAME + VERSION);
|
||||
}
|
||||
|
||||
CouchbaseContainer(String imageName) {
|
||||
super(imageName);
|
||||
|
||||
withNetwork(Network.SHARED);
|
||||
setWaitStrategy(new HttpWaitStrategy().forPath("/ui/index.html"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getLivenessCheckPortNumbers() {
|
||||
return Sets.newHashSet(getMappedPort(CouchbasePort.REST));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
if (this.clusterPassword.length() < REQUIRED_DEFAULT_PASSWORD_LENGTH) {
|
||||
logger().warn("The provided cluster admin password length is less then the default password policy length. "
|
||||
+ "Cluster start will fail if configured password requirements are not met.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
startProxy(getNetworkAliases().get(0));
|
||||
try {
|
||||
super.doStart();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
this.proxy.stop();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void startProxy(String networkAlias) {
|
||||
this.proxy = new SocatContainer().withNetwork(getNetwork());
|
||||
|
||||
for (CouchbasePort port : CouchbaseContainer.CouchbasePort.values()) {
|
||||
if (port.isDynamic()) {
|
||||
this.proxy.withTarget(port.getOriginalPort(), networkAlias);
|
||||
}
|
||||
else {
|
||||
this.proxy.addExposedPort(port.getOriginalPort());
|
||||
}
|
||||
}
|
||||
|
||||
this.proxy.setWaitStrategy(null);
|
||||
this.proxy.start();
|
||||
|
||||
ExecCreateCmdResponse createCmdResponse = this.dockerClient.execCreateCmd(this.proxy.getContainerId())
|
||||
.withCmd("sh", "-c",
|
||||
Stream.of(CouchbaseContainer.CouchbasePort.values())
|
||||
.map(port -> "/usr/bin/socat " + "TCP-LISTEN:" + port.getOriginalPort()
|
||||
+ ",fork,reuseaddr " + "TCP:" + networkAlias + ":" + getMappedPort(port))
|
||||
.collect(Collectors.joining(" & ", "true", "")))
|
||||
.exec();
|
||||
try {
|
||||
this.dockerClient.execStartCmd(createCmdResponse.getId()).exec(new ExecStartResultCallback())
|
||||
.awaitCompletion(10, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException("Interrupted docker start", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getExposedPorts() {
|
||||
return this.proxy.getExposedPorts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainerIpAddress() {
|
||||
return this.proxy.getContainerIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMappedPort(int originalPort) {
|
||||
return this.proxy.getMappedPort(originalPort);
|
||||
}
|
||||
|
||||
protected Integer getMappedPort(CouchbasePort port) {
|
||||
return getMappedPort(port.getOriginalPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getBoundPortNumbers() {
|
||||
return this.proxy.getBoundPortNumbers();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "ConstantConditions" })
|
||||
public void stop() {
|
||||
try {
|
||||
stopCluster();
|
||||
this.couchbaseCluster = null;
|
||||
this.couchbaseEnvironment = null;
|
||||
}
|
||||
finally {
|
||||
Stream.<Runnable>of(super::stop, this.proxy::stop).parallel().forEach(Runnable::run);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopCluster() {
|
||||
getCouchbaseCluster().disconnect();
|
||||
getCouchbaseEnvironment().shutdown();
|
||||
}
|
||||
|
||||
CouchbaseContainer withNewBucket(BucketSettings bucketSettings) {
|
||||
this.newBuckets.add(new BucketAndUserSettings(bucketSettings));
|
||||
return self();
|
||||
}
|
||||
|
||||
private void initUrlBase() {
|
||||
if (this.urlBase == null) {
|
||||
this.urlBase = String.format("http://%s:%s", getContainerIpAddress(), getMappedPort(CouchbasePort.REST));
|
||||
}
|
||||
}
|
||||
|
||||
void initCluster() throws Exception {
|
||||
String poolURL = "/pools/default";
|
||||
String poolPayload = "memoryQuota=" + URLEncoder.encode(this.memoryQuota, "UTF-8") + "&indexMemoryQuota="
|
||||
+ URLEncoder.encode(this.indexMemoryQuota, "UTF-8");
|
||||
|
||||
String setupServicesURL = "/node/controller/setupServices";
|
||||
StringBuilder servicePayloadBuilder = new StringBuilder();
|
||||
if (this.keyValue) {
|
||||
servicePayloadBuilder.append("kv,");
|
||||
}
|
||||
if (this.query) {
|
||||
servicePayloadBuilder.append("n1ql,");
|
||||
}
|
||||
if (this.index) {
|
||||
servicePayloadBuilder.append("index,");
|
||||
}
|
||||
if (this.fts) {
|
||||
servicePayloadBuilder.append("fts,");
|
||||
}
|
||||
String setupServiceContent = "services=" + URLEncoder.encode(servicePayloadBuilder.toString(), "UTF-8");
|
||||
|
||||
String webSettingsURL = "/settings/web";
|
||||
String webSettingsContent = "username=" + URLEncoder.encode(this.clusterUsername, "UTF-8") + "&password="
|
||||
+ URLEncoder.encode(this.clusterPassword, "UTF-8") + "&port=8091";
|
||||
|
||||
callCouchbaseRestAPI(poolURL, poolPayload);
|
||||
callCouchbaseRestAPI(setupServicesURL, setupServiceContent);
|
||||
callCouchbaseRestAPI(webSettingsURL, webSettingsContent);
|
||||
|
||||
createNodeWaitStrategy().waitUntilReady(this);
|
||||
callCouchbaseRestAPI("/settings/indexes",
|
||||
"indexerThreads=0&logLevel=info&maxRollbackPoints=5&storageMode=memory_optimized");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private HttpWaitStrategy createNodeWaitStrategy() {
|
||||
return new HttpWaitStrategy().forPath("/pools/default/")
|
||||
.withBasicCredentials(this.clusterUsername, this.clusterPassword).forStatusCode(HTTP_OK)
|
||||
.forResponsePredicate(response -> {
|
||||
try {
|
||||
return Optional.of(MAPPER.readTree(response)).map(n -> n.at("/nodes/0/status"))
|
||||
.map(JsonNode::asText).map("healthy"::equals).orElse(false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger().error("Unable to parse response {}", response);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void createBucket(BucketSettings bucketSetting, boolean primaryIndex) throws IOException {
|
||||
// Insert Bucket
|
||||
String payload = convertSettingsToParams(bucketSetting, false).build();
|
||||
callCouchbaseRestAPI("/pools/default/buckets/", payload);
|
||||
|
||||
// Check that the bucket is ready before moving on
|
||||
new HttpWaitStrategy().forPath("/pools/default/buckets/" + bucketSetting.name())
|
||||
.withBasicCredentials(this.clusterUsername, this.clusterPassword).forStatusCode(HTTP_OK)
|
||||
.waitUntilReady(this);
|
||||
|
||||
if (this.index && this.primaryIndex) {
|
||||
Bucket bucket = getCouchbaseCluster().bucket(bucketSetting.name());
|
||||
bucket.waitUntilReady(Duration.ofSeconds(10));
|
||||
if (primaryIndex) {
|
||||
getCouchbaseCluster().queryIndexes().createPrimaryIndex(bucketSetting.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void callCouchbaseRestAPI(String url, String payload) throws IOException {
|
||||
initUrlBase();
|
||||
|
||||
String fullUrl = this.urlBase + url;
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) ((new URL(fullUrl).openConnection()));
|
||||
httpConnection.setDoOutput(true);
|
||||
httpConnection.setRequestMethod("POST");
|
||||
httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
String encoded = encodeBase64String(
|
||||
(this.clusterUsername + ":" + this.clusterPassword).getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
httpConnection.setRequestProperty("Authorization", "Basic " + encoded);
|
||||
DataOutputStream out = new DataOutputStream(httpConnection.getOutputStream());
|
||||
out.writeBytes(payload);
|
||||
out.flush();
|
||||
httpConnection.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void containerIsCreated(String containerId) {
|
||||
patchConfig(STATIC_CONFIG, this::addMappedPorts);
|
||||
// capi needs a special configuration, see
|
||||
// https://developer.couchbase.com/documentation/server/current/install/install-ports.html
|
||||
patchConfig(CAPI_CONFIG, this::replaceCapiPort);
|
||||
}
|
||||
|
||||
private void patchConfig(String configLocation, ThrowingFunction<String, String> patchFunction) {
|
||||
String patchedConfig = copyFileFromContainer(configLocation,
|
||||
inputStream -> patchFunction.apply(IOUtils.toString(inputStream, StandardCharsets.UTF_8)));
|
||||
copyFileToContainer(Transferable.of(patchedConfig.getBytes(StandardCharsets.UTF_8)), configLocation);
|
||||
}
|
||||
|
||||
private String addMappedPorts(String originalConfig) {
|
||||
String portConfig = Stream.of(CouchbaseContainer.CouchbasePort.values()).filter(port -> !port.isDynamic())
|
||||
.map(port -> String.format("{%s, %d}.", port.name, getMappedPort(port)))
|
||||
.collect(Collectors.joining("\n"));
|
||||
return String.format("%s\n%s", originalConfig, portConfig);
|
||||
}
|
||||
|
||||
private String replaceCapiPort(String originalConfig) {
|
||||
return Arrays.stream(originalConfig.split("\n"))
|
||||
.map(s -> (s.matches("port\\s*=\\s*" + CouchbaseContainer.CouchbasePort.CAPI.getOriginalPort()))
|
||||
? "port = " + getMappedPort(CouchbaseContainer.CouchbasePort.CAPI) : s)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void containerIsStarted(InspectContainerResponse containerInfo) {
|
||||
try {
|
||||
initCluster();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Could not init cluster", e);
|
||||
}
|
||||
|
||||
if (!this.newBuckets.isEmpty()) {
|
||||
for (BucketAndUserSettings bucket : this.newBuckets) {
|
||||
try {
|
||||
createBucket(bucket.getBucketSettings(), this.primaryIndex);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Could not create bucket", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Cluster createCouchbaseCluster() {
|
||||
SeedNode seedNode = SeedNode.create(getContainerIpAddress(),
|
||||
Optional.of(getMappedPort(CouchbaseContainer.CouchbasePort.MEMCACHED)),
|
||||
Optional.of(getMappedPort(CouchbaseContainer.CouchbasePort.REST)));
|
||||
|
||||
return Cluster.connect(new HashSet<>(Collections.singletonList(seedNode)), ClusterOptions
|
||||
.clusterOptions(this.clusterUsername, this.clusterPassword).environment(getCouchbaseEnvironment()));
|
||||
}
|
||||
|
||||
synchronized ClusterEnvironment getCouchbaseEnvironment() {
|
||||
if (this.couchbaseEnvironment == null) {
|
||||
this.couchbaseEnvironment = createCouchbaseEnvironment();
|
||||
}
|
||||
return this.couchbaseEnvironment;
|
||||
}
|
||||
|
||||
synchronized Cluster getCouchbaseCluster() {
|
||||
if (this.couchbaseCluster == null) {
|
||||
this.couchbaseCluster = createCouchbaseCluster();
|
||||
}
|
||||
return this.couchbaseCluster;
|
||||
}
|
||||
|
||||
private ClusterEnvironment createCouchbaseEnvironment() {
|
||||
return ClusterEnvironment.builder().timeoutConfig(TimeoutConfig.kvTimeout(Duration.ofSeconds(10))).build();
|
||||
}
|
||||
|
||||
CouchbaseContainer withMemoryQuota(String memoryQuota) {
|
||||
this.memoryQuota = memoryQuota;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withIndexMemoryQuota(String indexMemoryQuota) {
|
||||
this.indexMemoryQuota = indexMemoryQuota;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withClusterAdmin(String username, String password) {
|
||||
this.clusterUsername = username;
|
||||
this.clusterPassword = password;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withKeyValue(boolean keyValue) {
|
||||
this.keyValue = keyValue;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withQuery(boolean query) {
|
||||
this.query = query;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withIndex(boolean index) {
|
||||
this.index = index;
|
||||
return self();
|
||||
}
|
||||
|
||||
CouchbaseContainer withPrimaryIndex(boolean primaryIndex) {
|
||||
this.primaryIndex = primaryIndex;
|
||||
return self();
|
||||
}
|
||||
|
||||
public CouchbaseContainer withFts(boolean fts) {
|
||||
this.fts = fts;
|
||||
return self();
|
||||
}
|
||||
|
||||
enum CouchbasePort {
|
||||
|
||||
REST("rest_port", 8091, true), CAPI("capi_port", 8092, false), QUERY("query_port", 8093, false), FTS(
|
||||
"fts_http_port", 8094, false), CBAS("cbas_http_port", 8095, false), EVENTING("eventing_http_port", 8096,
|
||||
false), MEMCACHED_SSL("memcached_ssl_port", 11207, false), MEMCACHED("memcached_port", 11210,
|
||||
false), REST_SSL("ssl_rest_port", 18091, true), CAPI_SSL("ssl_capi_port", 18092,
|
||||
false), QUERY_SSL("ssl_query_port", 18093, false), FTS_SSL("fts_ssl_port",
|
||||
18094, false), CBAS_SSL("cbas_ssl_port", 18095,
|
||||
false), EVENTING_SSL("eventing_ssl_port", 18096, false);
|
||||
|
||||
final String name;
|
||||
|
||||
final int originalPort;
|
||||
|
||||
final boolean dynamic;
|
||||
|
||||
CouchbasePort(String name, int originalPort, boolean dynamic) {
|
||||
this.name = name;
|
||||
this.originalPort = originalPort;
|
||||
this.dynamic = dynamic;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public int getOriginalPort() {
|
||||
return this.originalPort;
|
||||
}
|
||||
|
||||
public boolean isDynamic() {
|
||||
return this.dynamic;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class BucketAndUserSettings {
|
||||
|
||||
private final BucketSettings bucketSettings;
|
||||
|
||||
BucketAndUserSettings(BucketSettings bucketSettings) {
|
||||
this.bucketSettings = bucketSettings;
|
||||
}
|
||||
|
||||
BucketSettings getBucketSettings() {
|
||||
return this.bucketSettings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private UrlQueryStringBuilder convertSettingsToParams(final BucketSettings settings, boolean update) {
|
||||
UrlQueryStringBuilder params = UrlQueryStringBuilder.createForUrlSafeNames();
|
||||
|
||||
params.add("ramQuotaMB", settings.ramQuotaMB());
|
||||
params.add("replicaNumber", settings.numReplicas());
|
||||
params.add("flushEnabled", settings.flushEnabled() ? 1 : 0);
|
||||
params.add("maxTTL", settings.maxTTL());
|
||||
params.add("evictionPolicy", settings.ejectionPolicy().alias());
|
||||
params.add("compressionMode", settings.compressionMode().alias());
|
||||
|
||||
// The following values must not be changed on update
|
||||
if (!update) {
|
||||
params.add("name", settings.name());
|
||||
params.add("bucketType", settings.bucketType().alias());
|
||||
params.add("conflictResolutionType", settings.conflictResolutionType().alias());
|
||||
params.add("replicaIndex", settings.replicaIndexes() ? 1 : 0);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2012-2020 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import com.couchbase.client.core.env.IoConfig;
|
||||
import com.couchbase.client.core.env.TimeoutConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Io;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties.Timeouts;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CouchbaseProperties}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class CouchbasePropertiesTests {
|
||||
|
||||
@Test
|
||||
void ioHaveConsistentDefaults() {
|
||||
Io io = new CouchbaseProperties().getEnv().getIo();
|
||||
assertThat(io.getMinEndpoints()).isEqualTo(IoConfig.DEFAULT_NUM_KV_CONNECTIONS);
|
||||
assertThat(io.getMaxEndpoints()).isEqualTo(IoConfig.DEFAULT_MAX_HTTP_CONNECTIONS);
|
||||
assertThat(io.getIdleHttpConnectionTimeout()).isEqualTo(IoConfig.DEFAULT_IDLE_HTTP_CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void timeoutsHaveConsistentDefaults() {
|
||||
Timeouts timeouts = new CouchbaseProperties().getEnv().getTimeouts();
|
||||
assertThat(timeouts.getConnect()).isEqualTo(TimeoutConfig.DEFAULT_CONNECT_TIMEOUT);
|
||||
assertThat(timeouts.getKeyValue()).isEqualTo(TimeoutConfig.DEFAULT_KV_TIMEOUT);
|
||||
assertThat(timeouts.getQuery()).isEqualTo(TimeoutConfig.DEFAULT_QUERY_TIMEOUT);
|
||||
assertThat(timeouts.getView()).isEqualTo(TimeoutConfig.DEFAULT_VIEW_TIMEOUT);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,10 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.CouchbaseBucket;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -32,23 +29,13 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Stephane Nicoll
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CouchbaseTestConfiguration {
|
||||
class CouchbaseTestConfiguration {
|
||||
|
||||
private final Cluster cluster = mock(Cluster.class);
|
||||
|
||||
@Bean
|
||||
public Cluster couchbaseCluster() {
|
||||
Cluster couchbaseCluster() {
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClusterInfo couchbaseClusterInfo() {
|
||||
return mock(ClusterInfo.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bucket couchbaseClient() {
|
||||
return mock(CouchbaseBucket.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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
|
||||
*
|
||||
* https://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.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OnBootstrapHostsCondition}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class OnBootstrapHostsConditionTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(TestConfig.class);
|
||||
|
||||
@Test
|
||||
void bootstrapHostsNotDefined() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bootstrapHostsDefinedAsCommaSeparated() {
|
||||
this.contextRunner.withPropertyValues("spring.couchbase.bootstrap-hosts=value1")
|
||||
.run((context) -> assertThat(context).hasBean("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bootstrapHostsDefinedAsList() {
|
||||
this.contextRunner.withPropertyValues("spring.couchbase.bootstrap-hosts[0]=value1")
|
||||
.run((context) -> assertThat(context).hasBean("foo"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(OnBootstrapHostsCondition.class)
|
||||
static class TestConfig {
|
||||
|
||||
@Bean
|
||||
String foo() {
|
||||
return "foo";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,6 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
|
@ -40,8 +39,6 @@ import org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMappe
|
|||
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
|
||||
import org.springframework.data.couchbase.core.query.Consistency;
|
||||
import org.springframework.data.couchbase.repository.support.IndexManager;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -67,36 +64,6 @@ class CouchbaseDataAutoConfigurationTests {
|
|||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoIndexIsDisabledByDefault() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class).run((context) -> {
|
||||
IndexManager indexManager = context.getBean(IndexManager.class);
|
||||
assertThat(indexManager.isIgnoreViews()).isTrue();
|
||||
assertThat(indexManager.isIgnoreN1qlPrimary()).isTrue();
|
||||
assertThat(indexManager.isIgnoreN1qlSecondary()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void enableAutoIndex() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.withPropertyValues("spring.data.couchbase.auto-index=true").run((context) -> {
|
||||
IndexManager indexManager = context.getBean(IndexManager.class);
|
||||
assertThat(indexManager.isIgnoreViews()).isFalse();
|
||||
assertThat(indexManager.isIgnoreN1qlPrimary()).isFalse();
|
||||
assertThat(indexManager.isIgnoreN1qlSecondary()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeConsistency() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.withPropertyValues("spring.data.couchbase.consistency=eventually-consistent").run((context) -> {
|
||||
CouchbaseTemplate couchbaseTemplate = context.getBean(CouchbaseTemplate.class);
|
||||
assertThat(couchbaseTemplate.getDefaultConsistency()).isEqualTo(Consistency.EVENTUALLY_CONSISTENT);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void entityScanShouldSetInitialEntitySet() {
|
||||
|
@ -110,14 +77,14 @@ class CouchbaseDataAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void typeKeyDefault() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
this.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey())
|
||||
.isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeKeyCanBeCustomized() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
this.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class)
|
||||
.withPropertyValues("spring.data.couchbase.type-key=_custom")
|
||||
.run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey())
|
||||
.isEqualTo("_custom"));
|
||||
|
@ -134,7 +101,7 @@ class CouchbaseDataAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class CustomConversionsConfig {
|
||||
|
||||
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
|
||||
|
@ -146,7 +113,7 @@ class CouchbaseDataAutoConfigurationTests {
|
|||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city")
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class EntityScanConfig {
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.autoconfigure.data.couchbase;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.couchbase.config.CouchbaseConfigurationSupport;
|
||||
import org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -31,7 +31,7 @@ class CouchbaseDataPropertiesTests {
|
|||
|
||||
@Test
|
||||
void typeKeyHasConsistentDefault() {
|
||||
assertThat(new CouchbaseDataProperties().getTypeKey()).isEqualTo(new CouchbaseConfigurationSupport().typeKey());
|
||||
assertThat(new CouchbaseDataProperties().getTypeKey()).isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -14,22 +14,25 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.couchbase;
|
||||
package org.springframework.boot.autoconfigure.data.couchbase;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.OnPropertyListCondition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.CouchbaseClientFactory;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Condition to determine if {@code spring.couchbase.bootstrap-hosts} is specified.
|
||||
* Test configuration that mocks access to Couchbase.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Madhura Bhave
|
||||
* @author Eneias Silva
|
||||
*/
|
||||
class OnBootstrapHostsCondition extends OnPropertyListCondition {
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class CouchbaseMockConfiguration {
|
||||
|
||||
OnBootstrapHostsCondition() {
|
||||
super("spring.couchbase.bootstrap-hosts", () -> ConditionMessage.forCondition("Couchbase Bootstrap Hosts"));
|
||||
@Bean
|
||||
CouchbaseClientFactory couchbaseClientFactory() {
|
||||
return mock(CouchbaseClientFactory.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.CityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.ReactiveCityRepository;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
@ -62,7 +61,7 @@ class CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import({ CouchbaseTestConfiguration.class, Registrar.class })
|
||||
@Import({ CouchbaseMockConfiguration.class, Registrar.class })
|
||||
static class BaseConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
|
@ -34,7 +33,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.couchbase.config.BeanNames;
|
||||
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
|
||||
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
|
||||
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
|
||||
|
@ -56,13 +55,12 @@ class CouchbaseReactiveDataAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void disabledIfCouchbaseIsNotConfigured() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RxJavaCouchbaseTemplate.class));
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCouchbaseTemplate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatorIsPresent() {
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class));
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,7 +77,7 @@ class CouchbaseReactiveDataAutoConfigurationTests {
|
|||
@Test
|
||||
void customConversions() {
|
||||
this.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> {
|
||||
RxJavaCouchbaseTemplate template = context.getBean(RxJavaCouchbaseTemplate.class);
|
||||
ReactiveCouchbaseTemplate template = context.getBean(ReactiveCouchbaseTemplate.class);
|
||||
assertThat(
|
||||
template.getConverter().getConversionService().canConvert(CouchbaseProperties.class, Boolean.class))
|
||||
.isTrue();
|
||||
|
@ -87,7 +85,7 @@ class CouchbaseReactiveDataAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class CustomConversionsConfig {
|
||||
|
||||
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
|
||||
|
@ -99,7 +97,7 @@ class CouchbaseReactiveDataAutoConfigurationTests {
|
|||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city")
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class EntityScanConfig {
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.alt.couchbase.CityCouchbaseRepository;
|
||||
import org.springframework.boot.autoconfigure.data.alt.couchbase.ReactiveCityCouchbaseRepository;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
|
||||
|
@ -86,14 +85,14 @@ class CouchbaseReactiveRepositoriesAutoConfigurationTests {
|
|||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(EmptyDataPackage.class)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class NoRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
@ -101,7 +100,7 @@ class CouchbaseReactiveRepositoriesAutoConfigurationTests {
|
|||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(CouchbaseReactiveRepositoriesAutoConfigurationTests.class)
|
||||
@EnableCouchbaseRepositories(basePackageClasses = CityCouchbaseRepository.class)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class CustomizedConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
|
||||
import org.springframework.boot.autoconfigure.data.couchbase.city.CityRepository;
|
||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||
|
@ -82,14 +81,14 @@ class CouchbaseRepositoriesAutoConfigurationTests {
|
|||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(City.class)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class DefaultConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@TestAutoConfigurationPackage(EmptyDataPackage.class)
|
||||
@Import(CouchbaseTestConfiguration.class)
|
||||
@Import(CouchbaseMockConfiguration.class)
|
||||
static class NoRepositoryConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,10 +16,9 @@
|
|||
|
||||
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.annotation.Id;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.core.mapping.Field;
|
||||
|
||||
@Document
|
||||
public class City {
|
||||
|
|
Binary file not shown.
|
@ -215,14 +215,7 @@ bom {
|
|||
]
|
||||
}
|
||||
}
|
||||
library("Couchbase Cache Client", "2.1.0") {
|
||||
group("com.couchbase.client") {
|
||||
modules = [
|
||||
"couchbase-spring-cache"
|
||||
]
|
||||
}
|
||||
}
|
||||
library("Couchbase Client", "2.7.13") {
|
||||
library("Couchbase Client", "3.0.2") {
|
||||
group("com.couchbase.client") {
|
||||
modules = [
|
||||
"java-client"
|
||||
|
@ -1616,7 +1609,7 @@ bom {
|
|||
]
|
||||
}
|
||||
}
|
||||
library("Spring Data Releasetrain", "Neumann-M4") {
|
||||
library("Spring Data Releasetrain", "Neumann-BUILD-SNAPSHOT") {
|
||||
group("org.springframework.data") {
|
||||
imports = [
|
||||
"spring-data-releasetrain"
|
||||
|
|
|
@ -4473,20 +4473,18 @@ There are `spring-boot-starter-data-couchbase` and `spring-boot-starter-data-cou
|
|||
|
||||
[[boot-features-connecting-to-couchbase]]
|
||||
==== Connecting to Couchbase
|
||||
You can get a `Bucket` and `Cluster` by adding the Couchbase SDK and some configuration.
|
||||
You can get a `Cluster` by adding the Couchbase SDK and some configuration.
|
||||
The `spring.couchbase.*` properties can be used to customize the connection.
|
||||
Generally, you provide the bootstrap hosts, bucket name, and password, as shown in the following example:
|
||||
Generally, you provide the https://github.com/couchbaselabs/sdk-rfcs/blob/master/rfc/0011-connection-string.md[connection string], username, and password, as shown in the following example:
|
||||
|
||||
[source,properties,indent=0,configprops]
|
||||
----
|
||||
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
|
||||
spring.couchbase.bucket.name=my-bucket
|
||||
spring.couchbase.bucket.password=secret
|
||||
spring.couchbase.connection-string=couchbase://192.168.1.123
|
||||
spring.couchbase.username=user
|
||||
spring.couchbase.password=secret
|
||||
----
|
||||
|
||||
TIP: You need to provide _at least_ the bootstrap host(s), in which case the bucket name is `default` and the password is an empty String.
|
||||
|
||||
It is also possible to customize some of the `CouchbaseEnvironment` settings.
|
||||
It is also possible to customize some of the `ClusterEnvironment` settings.
|
||||
For instance, the following configuration changes the timeout to use to open a new `Bucket` and enables SSL support:
|
||||
|
||||
[source,properties,indent=0,configprops]
|
||||
|
@ -4497,18 +4495,24 @@ For instance, the following configuration changes the timeout to use to open a n
|
|||
----
|
||||
|
||||
TIP: Check the `spring.couchbase.env.*` properties for more details.
|
||||
To take more control, one or more `CouchbaseEnvironmentBuilderCustomizer` beans can be used.
|
||||
To take more control, one or more `ClusterEnvironmentBuilderCustomizer` beans can be used.
|
||||
|
||||
|
||||
|
||||
[[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 the https://docs.spring.io/spring-data/couchbase/docs/current/reference/html/[reference documentation].
|
||||
For complete details of Spring Data Couchbase, refer to the {spring-data-couchbase-docs}[reference documentation].
|
||||
|
||||
You can inject an auto-configured `CouchbaseTemplate` instance as you would with any other Spring Bean, provided a _default_ `CouchbaseConfigurer` is available (which happens when you enable Couchbase support, as explained earlier).
|
||||
You can inject an auto-configured `CouchbaseTemplate` instance as you would with any other Spring Bean, provided a `CouchbaseClientFactory` bean is available.
|
||||
This happens when a `Cluster` is availabe, as described above, and a bucket name as been specified:
|
||||
|
||||
The following examples shows how to inject a Couchbase bean:
|
||||
[source,properties,indent=0,configprops]
|
||||
----
|
||||
spring.data.couchbase.bucket-name=my-bucket
|
||||
----
|
||||
|
||||
The following examples shows how to inject a `CouchbaseTemplate` bean:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
|
@ -4529,9 +4533,9 @@ The following examples shows how to inject a Couchbase bean:
|
|||
|
||||
There are a few beans that you can define in your own configuration to override those provided by the auto-configuration:
|
||||
|
||||
* A `CouchbaseTemplate` `@Bean` with a name of `couchbaseTemplate`.
|
||||
* An `IndexManager` `@Bean` with a name of `couchbaseIndexManager`.
|
||||
* A `CouchbaseMappingContext` `@Bean` with a name of `couchbaseMappingContext`.
|
||||
* A `CustomConversions` `@Bean` with a name of `couchbaseCustomConversions`.
|
||||
* A `CouchbaseTemplate` `@Bean` with a name of `couchbaseTemplate`.
|
||||
|
||||
To avoid hard-coding those names in your own config, you can reuse `BeanNames` provided by Spring Data Couchbase.
|
||||
For instance, you can customize the converters to use, as follows:
|
||||
|
@ -4551,8 +4555,6 @@ For instance, you can customize the converters to use, as follows:
|
|||
}
|
||||
----
|
||||
|
||||
TIP: If you want to fully bypass the auto-configuration for Spring Data Couchbase, provide your own implementation of `org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration`.
|
||||
|
||||
|
||||
|
||||
[[boot-features-ldap]]
|
||||
|
|
|
@ -10,8 +10,7 @@ def caches = [
|
|||
"com.github.ben-manes.caffeine:caffeine"
|
||||
],
|
||||
"couchbase": [
|
||||
"com.couchbase.client:java-client",
|
||||
"com.couchbase.client:couchbase-spring-cache"
|
||||
project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-couchbase")
|
||||
],
|
||||
"ehcache": [
|
||||
"javax.cache:cache-api",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
|
@ -16,10 +16,9 @@
|
|||
|
||||
package smoketest.data.couchbase;
|
||||
|
||||
import com.couchbase.client.java.repository.annotation.Field;
|
||||
import com.couchbase.client.java.repository.annotation.Id;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.couchbase.core.mapping.Document;
|
||||
import org.springframework.data.couchbase.core.mapping.Field;
|
||||
|
||||
@Document
|
||||
public class User {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
spring.couchbase.bootstrap-hosts=localhost
|
||||
spring.couchbase.connection-string=couchbase://127.0.0.1
|
||||
spring.couchbase.username=admin
|
||||
spring.couchbase.password=secret
|
||||
|
||||
spring.couchbase.env.timeouts.connect=10000
|
||||
spring.couchbase.env.timeouts.socket-connect=10000
|
||||
spring.couchbase.env.timeouts.connect=15s
|
||||
|
||||
spring.data.couchbase.auto-index=true
|
||||
spring.data.couchbase.bucket-name=default
|
||||
|
|
|
@ -46,4 +46,5 @@
|
|||
<suppress files="[\\/]src[\\/]intTest[\\/]java[\\/]" checks="SpringJavadoc" message="\@since" />
|
||||
<suppress files="LinuxDomainSocket" checks="FinalClass" message="SockaddrUn" />
|
||||
<suppress files="BsdDomainSocket" checks="FinalClass" message="SockaddrUn" />
|
||||
<suppress files="[\\/]org.springframework.boot.autoconfigure.couchbase.CouchbaseContainer.java$" checks=".*" />
|
||||
</suppressions>
|
||||
|
|
Loading…
Reference in New Issue