add abstract Configuration

the proxy for CouchbaseEnvironment allows shared env to be added to Spring.
bean names have been set back to be prefixed by "couchbase".
This commit is contained in:
Simon Baslé
2015-06-16 18:12:40 +02:00
parent b246614263
commit 1059329646
3 changed files with 448 additions and 2 deletions

View File

@@ -0,0 +1,199 @@
/*
* Copyright 2012-2015 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.config;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
import org.springframework.data.mapping.model.FieldNamingStrategy;
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Base class for Spring Data Couchbase configuration using JavaConfig.
*
* @author Michael Nitschinger
* @author Simon Baslé
*/
@Configuration
public abstract class AbstractCouchbaseConfiguration {
/**
* The list of hostnames (or IP addresses) to bootstrap from.
*
* @return the list of bootstrap hosts.
*/
protected abstract List<String> bootstrapHosts();
/**
* The name of the bucket to connect to.
*
* @return the name of the bucket.
*/
protected abstract String getBucketName();
/**
* The password of the bucket (can be an empty string).
*
* @return the password of the bucket.
*/
protected abstract String getBucketPassword();
/**
* Override this method if you use Couchbase outside of the Spring context.
* If non-null, defines the {@link CouchbaseEnvironment} to use for connection (it is your
* responsibility to shutdown() it).
*
* @return a pre-existing environment managed outside of Spring, or null if instead a managed
* environment is to be used.
*/
protected CouchbaseEnvironment sharedEnvironment() {
return null; //assume most of the time we'll create a dedicated one
}
/**
* Override this method if you want a customized {@link CouchbaseEnvironment} but only
* use it in the Spring context. This environment will be managed by Spring, which will
* call its shutdown() method upon bean destruction.
*
* @return a customized environment to be managed by Spring, defaults to a {@link DefaultCouchbaseEnvironment}.
*/
protected CouchbaseEnvironment managedEnvironment() {
return DefaultCouchbaseEnvironment.create();
}
@Bean(destroyMethod = "shutdown", name = BeanNames.COUCHBASE_ENV)
@Conditional(ConfigurationCondition.class)
public CouchbaseEnvironment couchbaseEnvironment() {
CouchbaseEnvironment env = sharedEnvironment();
if (env != null) {
//the shared environment shouldn't have its shutdown method called when
//the bean is destroyed, it is the responsibility of the user to destroy it.
return new CouchbaseEnvironmentNoShutdownProxy(env);
} else {
return managedEnvironment();
}
}
/**
* Returns the {@link Cluster} instance to connect to.
*
* @throws Exception on Bean construction failure.
*/
@Bean(destroyMethod = "disconnect", name = BeanNames.COUCHBASE_CLUSTER)
public Cluster couchbaseCluster() throws Exception {
return CouchbaseCluster.create(couchbaseEnvironment(), bootstrapHosts());
}
/**
* Return the {@link Bucket} instance to connect to.
*
* @throws Exception on Bean construction failure.
*/
@Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET)
public Bucket couchbaseClient() throws Exception {
//@Bean method can use another @Bean method in the same @Configuration by directly invoking it
return couchbaseCluster().openBucket(getBucketName(), getBucketPassword());
}
/**
* Creates a {@link CouchbaseTemplate}.
*
* @throws Exception on Bean construction failure.
*/
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
public CouchbaseTemplate couchbaseTemplate() throws Exception {
//TODO use mappingCouchbaseConverter and translationService when implemented
return new CouchbaseTemplate(couchbaseClient());
}
//TODO create beans for mappingCouchbaseConverter, translationService, couchbaseMappingContext when implemented
//TODO for mappingCouchbaseConverter, allow registering of customConversions
/**
* Scans the mapping base package for classes annotated with {@link Document}.
*
* @throws ClassNotFoundException if initial entity sets could not be loaded.
*/
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
String basePackage = getMappingBasePackage();
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(), AbstractCouchbaseConfiguration.class.getClassLoader()));
}
}
return initialEntitySet;
}
/**
* Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
* class (the concrete class, not this one here) by default.
* <p/>
* <p>So if you have a {@code com.acme.AppConfig} extending {@link AbstractCouchbaseConfiguration} the base package
* will be considered {@code com.acme} unless the method is overridden to implement alternate behavior.</p>
*
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
* entities.
*/
protected String getMappingBasePackage() {
return getClass().getPackage().getName();
}
/**
* Set to true if field names should be abbreviated with the {@link CamelCaseAbbreviatingFieldNamingStrategy}.
*
* @return true if field names should be abbreviated, default is false.
*/
protected boolean abbreviateFieldNames() {
return false;
}
/**
* Configures a {@link FieldNamingStrategy} on the CouchbaseMappingContext instance created.
*
* @return the naming strategy.
*/
protected FieldNamingStrategy fieldNamingStrategy() {
//TODO implement a CouchbaseMappingContext, use this method (update link in javadoc)
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE;
}
}

View File

@@ -24,15 +24,19 @@ package org.springframework.data.couchbase.config;
*/
public class BeanNames {
/**
* Refers to the <couchbase:env /> bean.
*/
static final String COUCHBASE_ENV = "couchbaseEnv";
/**
* Refers to the "<couchbase:cluster />" bean.
*/
static final String COUCHBASE_CLUSTER = "cluster";
static final String COUCHBASE_CLUSTER = "couchbaseCluster";
/**
* Refers to the "<couchbase:bucket />" bean.
*/
static final String COUCHBASE_BUCKET = "bucket";
static final String COUCHBASE_BUCKET = "couchbaseBucket";
/**
* Refers to the "<couchbase:template />" bean.
@@ -44,4 +48,5 @@ public class BeanNames {
*/
static final String TRANSLATION_SERVICE = "translationService";
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright 2012-2015 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.config;
import com.couchbase.client.core.event.EventBus;
import com.couchbase.client.core.retry.RetryStrategy;
import com.couchbase.client.core.time.Delay;
import com.couchbase.client.deps.io.netty.channel.EventLoopGroup;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import rx.Observable;
import rx.Scheduler;
/**
* A proxy around a {@link CouchbaseEnvironment} that prevents its {@link #shutdown()} method
* to be invoked. Useful when the delegate is not to be lifecycle-managed by Spring.
*
* @author Simon Baslé
*/
public class CouchbaseEnvironmentNoShutdownProxy implements CouchbaseEnvironment {
private final CouchbaseEnvironment delegate;
public CouchbaseEnvironmentNoShutdownProxy(CouchbaseEnvironment delegate) {
this.delegate = delegate;
}
@Override
public Observable<Boolean> shutdown() {
return Observable.just(false);
}
//===== DELEGATION METHODS =====
@Override
public EventLoopGroup ioPool() {
return delegate.ioPool();
}
@Override
public Scheduler scheduler() {
return delegate.scheduler();
}
@Override
public boolean dcpEnabled() {
return delegate.dcpEnabled();
}
@Override
public boolean sslEnabled() {
return delegate.sslEnabled();
}
@Override
public String sslKeystoreFile() {
return delegate.sslKeystoreFile();
}
@Override
public String sslKeystorePassword() {
return delegate.sslKeystorePassword();
}
@Override
public boolean queryEnabled() {
return delegate.queryEnabled();
}
@Override
public int queryPort() {
return delegate.queryPort();
}
@Override
public boolean bootstrapHttpEnabled() {
return delegate.bootstrapHttpEnabled();
}
@Override
public boolean bootstrapCarrierEnabled() {
return delegate.bootstrapCarrierEnabled();
}
@Override
public int bootstrapHttpDirectPort() {
return delegate.bootstrapHttpDirectPort();
}
@Override
public int bootstrapHttpSslPort() {
return delegate.bootstrapHttpSslPort();
}
@Override
public int bootstrapCarrierDirectPort() {
return delegate.bootstrapCarrierDirectPort();
}
@Override
public int bootstrapCarrierSslPort() {
return delegate.bootstrapCarrierSslPort();
}
@Override
public int ioPoolSize() {
return delegate.ioPoolSize();
}
@Override
public int computationPoolSize() {
return delegate.computationPoolSize();
}
@Override
public Delay observeIntervalDelay() {
return delegate.observeIntervalDelay();
}
@Override
public Delay reconnectDelay() {
return delegate.reconnectDelay();
}
@Override
public Delay retryDelay() {
return delegate.retryDelay();
}
@Override
public int requestBufferSize() {
return delegate.requestBufferSize();
}
@Override
public int responseBufferSize() {
return delegate.responseBufferSize();
}
@Override
public int kvEndpoints() {
return delegate.kvEndpoints();
}
@Override
public int viewEndpoints() {
return delegate.viewEndpoints();
}
@Override
public int queryEndpoints() {
return delegate.queryEndpoints();
}
@Override
public String userAgent() {
return delegate.userAgent();
}
@Override
public String packageNameAndVersion() {
return delegate.packageNameAndVersion();
}
@Override
public RetryStrategy retryStrategy() {
return delegate.retryStrategy();
}
@Override
public long maxRequestLifetime() {
return delegate.maxRequestLifetime();
}
@Override
public long autoreleaseAfter() {
return delegate.autoreleaseAfter();
}
@Override
public long keepAliveInterval() {
return delegate.keepAliveInterval();
}
@Override
public EventBus eventBus() {
return delegate.eventBus();
}
@Override
public boolean bufferPoolingEnabled() {
return delegate.bufferPoolingEnabled();
}
@Override
public long managementTimeout() {
return delegate.managementTimeout();
}
@Override
public long queryTimeout() {
return delegate.queryTimeout();
}
@Override
public long viewTimeout() {
return delegate.viewTimeout();
}
@Override
public long kvTimeout() {
return delegate.kvTimeout();
}
@Override
public long connectTimeout() {
return delegate.connectTimeout();
}
@Override
public long disconnectTimeout() {
return delegate.disconnectTimeout();
}
@Override
public boolean dnsSrvEnabled() {
return delegate.dnsSrvEnabled();
}
}