DATACOUCH-21 - Documentation and Formatting improvements

This commit is contained in:
Michael Nitschinger
2013-07-18 12:28:26 +02:00
parent ab252f8924
commit 4511387d8e
40 changed files with 725 additions and 191 deletions

View File

@@ -22,9 +22,11 @@ import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
/**
* The CouchbaseCache class implements the Spring Cache interface
* on top of Couchbase Server and the Couchbase Java SDK.
* The {@link CouchbaseCache} class implements the Spring Cache interface on top of Couchbase Server and the Couchbase
* Java SDK.
*
* @see <a href="http://static.springsource.org/spring/docs/current/spring-framework-reference/html/cache.html">
* Official Spring Cache Reference</a>
* @author Michael Nitschinger
*/
public class CouchbaseCache implements Cache {
@@ -65,7 +67,7 @@ public class CouchbaseCache implements Cache {
* @return the actual CouchbaseClient instance.
*/
public final CouchbaseClient getNativeCache() {
return this.client;
return client;
}
/**
@@ -76,7 +78,7 @@ public class CouchbaseCache implements Cache {
*/
public final ValueWrapper get(final Object key) {
String documentId = key.toString();
Object result = this.client.get(documentId);
Object result = client.get(documentId);
return (result != null ? new SimpleValueWrapper(result) : null);
}
@@ -88,7 +90,7 @@ public class CouchbaseCache implements Cache {
*/
public final void put(final Object key, final Object value) {
String documentId = key.toString();
this.client.set(documentId, 0, value);
client.set(documentId, 0, value);
}
/**
@@ -98,7 +100,7 @@ public class CouchbaseCache implements Cache {
*/
public final void evict(final Object key) {
String documentId = key.toString();
this.client.delete(documentId);
client.delete(documentId);
}
/**
@@ -108,7 +110,7 @@ public class CouchbaseCache implements Cache {
* Also note that "flush" may not be enabled on the bucket.
*/
public final void clear() {
this.client.flush();
client.flush();
}
}

View File

@@ -25,11 +25,10 @@ import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
/**
* The CouchbaseCacheManager orchestrates CouchbaseCache instances.
* The {@link CouchbaseCacheManager} orchestrates {@link CouchbaseCache} instances.
*
* Since more than one current CouchbaseClient connection can be used
* for caching, the CouchbaseCacheManager orchestrates and handles
* them for the Spring Cache abstraction layer.
* Since more than one current {@link CouchbaseClient} connection can be used for caching, the
* {@link CouchbaseCacheManager} orchestrates and handles them for the Spring Cache abstraction layer.
*
* @author Michael Nitschinger
*/
@@ -55,7 +54,7 @@ public class CouchbaseCacheManager extends AbstractCacheManager {
* @return the actual CouchbaseClient instances.
*/
public final HashMap<String, CouchbaseClient> getClients() {
return this.clients;
return clients;
}
/**
@@ -67,7 +66,7 @@ public class CouchbaseCacheManager extends AbstractCacheManager {
protected final Collection<? extends Cache> loadCaches() {
Collection<Cache> caches = new LinkedHashSet<Cache>();
for (Map.Entry<String, CouchbaseClient> cache : this.clients.entrySet()) {
for (Map.Entry<String, CouchbaseClient> cache : clients.entrySet()) {
caches.add(new CouchbaseCache(cache.getKey(), cache.getValue()));
}

View File

@@ -25,7 +25,7 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.couchbase.core.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.Document;
@@ -42,12 +42,16 @@ public abstract class AbstractCouchbaseConfiguration {
/**
* Return the {@link CouchbaseClient} instance to connect to.
*
* @throws Exception on Bean construction failure.
*/
@Bean
public abstract CouchbaseClient couchbaseClient() throws Exception;
/**
* Creates a {@link CouchbaseTemplate}.
*
* @throws Exception on Bean construction failure.
*/
@Bean
public CouchbaseTemplate couchbaseTemplate() throws Exception {
@@ -55,8 +59,9 @@ public abstract class AbstractCouchbaseConfiguration {
}
/**
* Creates a {@link MappingCouchbaseConverter} using the configured {@link
* #couchbaseMappingContext}.
* Creates a {@link MappingCouchbaseConverter} using the configured {@link #couchbaseMappingContext}.
*
* @throws Exception on Bean construction failure.
*/
@Bean
public MappingCouchbaseConverter mappingCouchbaseConverter() throws Exception {
@@ -64,8 +69,9 @@ public abstract class AbstractCouchbaseConfiguration {
}
/**
* Creates a {@link CouchbaseMappingContext} equipped with entity classes
* scanned from the mapping base package.
* Creates a {@link CouchbaseMappingContext} equipped with entity classes scanned from the mapping base package.
*
* @throws Exception on Bean construction failure.
*/
@Bean
public CouchbaseMappingContext couchbaseMappingContext() throws Exception {
@@ -76,12 +82,14 @@ public abstract class AbstractCouchbaseConfiguration {
/**
* Scans the mapping base package for classes annotated with {@link Document}.
*
* @throws ClassNotFoundException if intial 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)) {
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider =
new ClassPathScanningCandidateComponentProvider(false);
componentProvider.addIncludeFilter(
@@ -100,15 +108,14 @@ public abstract class AbstractCouchbaseConfiguration {
}
/**
* 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. 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.
* 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.
*
* @return the base package to scan for mapped {@link Document} classes or
* {@literal null} to not enable scanning for entities.
* <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();

View File

@@ -17,12 +17,18 @@
package org.springframework.data.couchbase.config;
/**
* Contains default bean names that will be used when no "id" is supplied to the beans.
*
* @author Michael Nitschinger
*/
public class BeanNames {
static final String MAPPING_CONTEXT = "mappingContext";
/**
* Refers to the "<couchbase:couchbase />" bean.
*/
static final String COUCHBASE = "couchbase";
static final String DB_FACTORY = "couchbaseDbFactory";
static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter";
/**
* Refers to the "<couchbase:template />" bean.
*/
static final String COUCHBASE_TEMPLATE = "couchbaseTemplate";
}

View File

@@ -28,12 +28,22 @@ import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Enables Parsing of "<couchbase:jmx />" configurations.
* Enables Parsing of the "<couchbase:jmx />" configuration bean.
*
* In order to enable JMX, different JmxComponents need to be registered. The dependency to the original
* {@link com.couchbase.client.CouchbaseClient} object is solved by through the "couchbase-ref" attribute.
*
* @author Michael Nitschinger
*/
public class CouchbaseJmxParser implements BeanDefinitionParser {
/**
* Parse the element and dispatch the registration of the JMX components.
*
* @param element the XML element which contains the attributes.
* @param parserContext encapsulates the parsing state and configuration.
* @return null, because no bean instance needs to be returned.
*/
public BeanDefinition parse(final Element element, final ParserContext parserContext) {
String name = element.getAttribute("couchbase-ref");
if (!StringUtils.hasText(name)) {
@@ -43,7 +53,14 @@ public class CouchbaseJmxParser implements BeanDefinitionParser {
return null;
}
protected void registerJmxComponents(String refName, Element element, ParserContext parserContext) {
/**
* Register the JMX components in the context.
*
* @param refName the reference name to the couchbase client.
* @param element the XML element which contains the attributes.
* @param parserContext encapsulates the parsing state and configuration.
*/
protected void registerJmxComponents(final String refName, final Element element, final ParserContext parserContext) {
Object eleSource = parserContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
@@ -53,8 +70,17 @@ public class CouchbaseJmxParser implements BeanDefinitionParser {
parserContext.registerComponent(compositeDef);
}
protected void createBeanDefEntry(Class<?> clazz, CompositeComponentDefinition compositeDef,
String refName, Object eleSource, ParserContext parserContext) {
/**
* Creates Bean Definitions for JMX components and adds them as a nested component.
*
* @param clazz the class type to register.
* @param compositeDef component that can hold nested components.
* @param refName the reference name to the couchbase client.
* @param eleSource source element to reference.
* @param parserContext encapsulates the parsing state and configuration.
*/
protected void createBeanDefEntry(final Class<?> clazz, final CompositeComponentDefinition compositeDef,
final String refName, final Object eleSource, final ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
builder.getRawBeanDefinition().setSource(eleSource);
builder.addConstructorArgReference(refName);

View File

@@ -24,11 +24,17 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
/**
* {@link org.springframework.beans.factory.xml.NamespaceHandler} for Couchbase configuration.
*
* This handler acts as a container for one or more bean parsers and registers them. During parsing, the elements
* get analyzed and the appropriate registered parser is called.
*
* @author Michael Nitschinger
*/
public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
/**
* Register bean definition parsers in the namespace handler.
*/
public final void init() {
RepositoryConfigurationExtension extension = new CouchbaseRepositoryConfigurationExtension();
registerBeanDefinitionParser("repositories", new RepositoryBeanDefinitionParser(extension));

View File

@@ -31,19 +31,32 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
/**
* Parser for "<couchbase:couchbase />" definitions.
* Parser for "<couchbase:couchbase />" bean definitions.
*
* The outcome of this bean definition parser will be a constructed {@link CouchbaseClient}.
*
* @author Michael Nitschinger
*/
public class CouchbaseParser extends AbstractSingleBeanDefinitionParser {
/**
* Defines the bean class that will be constructed.
*
* @param element the XML element which contains the attributes.
* @return the class type to instantiate.
*/
@Override
protected Class getBeanClass(final Element element) {
return CouchbaseClient.class;
}
/**
* Parse the bean definition and build up the bean.
*
* @param element the XML element which contains the attributes.
* @param bean the builder which builds the bean.
*/
@Override
protected void doParse(final Element element, final BeanDefinitionBuilder bean) {
String host = element.getAttribute("host");
@@ -57,12 +70,30 @@ public class CouchbaseParser extends AbstractSingleBeanDefinitionParser {
StringUtils.hasText(password) ? password : CouchbaseFactoryBean.DEFAULT_PASSWORD);
}
/**
* Resolve the bean ID and assign a default if not set.
*
* @param element the XML element which contains the attributes.
* @param definition the bean definition to work with.
* @param parserContext encapsulates the parsing state and configuration.
* @return the ID to work with.
*/
@Override
protected String resolveId(final Element element, final AbstractBeanDefinition definition,
final ParserContext parserContext) {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE;
}
/**
* Convert a list of hosts into a URI format that can be used by the {@link CouchbaseClient}.
*
* To make it simple to use, the list of hosts can be passed in as a comma separated list. This list gets parsed
* and converted into a URI format that is suitable for the underlying {@link CouchbaseClient} object.
*
* @param hosts the host list to convert.
* @return the converted list with URIs.
*/
private List<URI> convertHosts(final String hosts) {
String[] split = hosts.split(",");
List<URI> nodes = new ArrayList<URI>();

View File

@@ -25,21 +25,46 @@ import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for "<couchbase:template />" bean definitions.
*
* The outcome of this bean definition parser will be a constructed {@link CouchbaseTemplate}.
*
* @author Michael Nitschinger
*/
public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser {
/**
* Resolve the bean ID and assign a default if not set.
*
* @param element the XML element which contains the attributes.
* @param definition the bean definition to work with.
* @param parserContext encapsulates the parsing state and configuration.
* @return the ID to work with.
*/
@Override
protected String resolveId(final Element element, final AbstractBeanDefinition definition,
final ParserContext parserContext) {
String id = super.resolveId(element, definition, parserContext);
return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_TEMPLATE;
}
/**
* Defines the bean class that will be constructed.
*
* @param element the XML element which contains the attributes.
* @return the class type to instantiate.
*/
@Override
protected Class getBeanClass(final Element element) {
return CouchbaseTemplate.class;
}
/**
* Parse the bean definition and build up the bean.
*
* @param element the XML element which contains the attributes.
* @param bean the builder which builds the bean.
*/
@Override
protected void doParse(final Element element, final BeanDefinitionBuilder bean) {
String converterRef = element.getAttribute("converter-ref");

View File

@@ -20,8 +20,20 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* Defines the callback which will be wrapped and executed on a bucket.
*
* @author Michael Nitschinger
*/
public interface BucketCallback<T> {
/**
* The enclosed body will be executed on the connected bucket.
*
* @return the result of the enclosed execution.
* @throws TimeoutException if the enclosed operation timed out.
* @throws ExecutionException if the result could not be retrieved because of a thrown exception before.
* @throws InterruptedException if the enclosed operation was interrupted.
*/
T doInBucket() throws TimeoutException, ExecutionException, InterruptedException;
}

View File

@@ -35,10 +35,9 @@ import java.util.concurrent.CancellationException;
/**
* Simple {@link PersistenceExceptionTranslator} for Couchbase.
*
* Convert the given runtime exception to an appropriate exception from the
* {@code org.springframework.dao} hierarchy. Return {@literal null} if no translation
* is appropriate: any other exception may have resulted from user code, and should not
* be translated.
* Convert the given runtime exception to an appropriate exception from the {@code org.springframework.dao} hierarchy.
* Return {@literal null} if no translation is appropriate: any other exception may have resulted from user code, and
* should not be translated.
*
* @author Michael Nitschinger
*/

View File

@@ -34,76 +34,183 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Convenient Factory for configuring Couchbase.
* Convenient Factory for configuring a {@link CouchbaseClient}.
*
* To set the properties correctly on the {@link CouchbaseClient} a {@link CouchbaseConnectionFactoryBuilder} is used.
* After all properties are set, the client is constructed and used.
*
* @author Michael Nitschinger
*/
public class CouchbaseFactoryBean implements FactoryBean<CouchbaseClient>, InitializingBean,
DisposableBean, PersistenceExceptionTranslator {
/**
* Defines the default hostname to be used if no other list is supplied.
*/
public static final String DEFAULT_NODE = "127.0.0.1";
/**
* Defines the default bucket name to be used if no other bucket name is supplied.
*/
public static final String DEFAULT_BUCKET = "default";
/**
* Defines the password of the default bucket.
*/
public static final String DEFAULT_PASSWORD = "";
/**
* Holds the enclosed {@link CouchbaseClient}.
*/
private CouchbaseClient couchbaseClient;
private PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
private String bucket;
private String password;
private List<URI> nodes;
private CouchbaseConnectionFactoryBuilder builder = new CouchbaseConnectionFactoryBuilder();
/**
* The exception translator is used to properly map exceptions to spring-type exceptions.
*/
private PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
/**
* Contains the actual bucket name.
*/
private String bucket;
/**
* Contains the actual bucket password.
*/
private String password;
/**
* Contains the list of nodes to connect to.
*/
private List<URI> nodes;
/**
* The builder which allows to customize client settings.
*/
private final CouchbaseConnectionFactoryBuilder builder = new CouchbaseConnectionFactoryBuilder();
/**
* Set the observe poll interval in miliseconds.
*
* @param interval the observe poll interval.
*/
public void setObservePollInterval(final int interval) {
builder.setObsPollInterval(interval);
}
/**
* Set the maximum number of polls.
*
* @param max the maximum number of polls.
*/
public void setObservePollMax(final int max) {
builder.setObsPollMax(max);
}
/**
* Set the reconnect threshold time in seconds.
*
* @param time the reconnect threshold time.
*/
public void setReconnectThresholdTime(final int time) {
builder.setReconnectThresholdTime(time, TimeUnit.SECONDS);
}
/**
* Set the view timeout in miliseconds.
*
* @param timeout the view timeout.
*/
public void setViewTimeout(final int timeout) {
builder.setViewTimeout(timeout);
}
/**
* Set the failure mode if memcached buckets are used.
*
* See the proper values of {@link FailureMode} to use.
*
* @param mode the failure mode.
*/
public void setFailureMode(final String mode) {
builder.setFailureMode(FailureMode.valueOf(mode));
}
/**
* Set the operation timeout in miliseconds.
*
* @param timeout the operation timeout.
*/
public void setOpTimeout(final int timeout) {
builder.setOpTimeout(timeout);
}
/**
* Set the operation queue maximum block time in miliseconds.
*
* @param time the operation queue maximum block time.
*/
public void setOpQueueMaxBlockTime(final int time) {
builder.setOpQueueMaxBlockTime(time);
}
/**
* Shutdown the client when the bean is destroyed.
*
* @throws Exception if shutdown failed.
*/
@Override
public void destroy() throws Exception {
couchbaseClient.shutdown();
}
/**
* Return the underlying {@link CouchbaseClient}.
*
* @return the client object.
* @throws Exception if returning the client failed.
*/
@Override
public CouchbaseClient getObject() throws Exception {
return couchbaseClient;
}
/**
* Returns the object type of the client.
*
* @return the {@link CouchbaseClient} class.
*/
@Override
public Class<?> getObjectType() {
return CouchbaseClient.class;
}
/**
* The client should be returned as a singleton.
*
* @return returns true.
*/
@Override
public boolean isSingleton() {
return true;
}
/**
* Set the nodes as an array of URIs.
*
* @param nodes the nodes to connect to.
*/
public void setNodes(final URI[] nodes) {
this.nodes = filterNonNullElementsAsList(nodes);
}
/**
* Convert the array of elements to a list and filter empty or null elements.
*
* @param elements the elements to convert.
* @param <T> the type of the elements.
* @return the converted list.
*/
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
if (elements == null) {
return Collections.emptyList();
@@ -119,6 +226,11 @@ public class CouchbaseFactoryBean implements FactoryBean<CouchbaseClient>, Initi
return Collections.unmodifiableList(candidateElements);
}
/**
* Instantiate the {@link CouchbaseClient}.
*
* @throws Exception if something goes wrong during instantiation.
*/
@Override
public void afterPropertiesSet() throws Exception {
nodes = nodes != null ? nodes : Arrays.asList(new URI("http://" + DEFAULT_NODE + ":8091/pools"));
@@ -129,8 +241,15 @@ public class CouchbaseFactoryBean implements FactoryBean<CouchbaseClient>, Initi
couchbaseClient = new CouchbaseClient(factory);
}
/**
* Translate exception if possible.
*
* @param ex the exception to translate.
* @return the translate exception.
*/
@Override
public DataAccessException translateExceptionIfPossible(final RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
}

View File

@@ -25,6 +25,8 @@ import com.couchbase.client.protocol.views.ViewResponse;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
/**
* Defines common operations on the Couchbase data source, most commonly implemented by {@link CouchbaseTemplate}.
*
* @author Michael Nitschinger
*/
public interface CouchbaseOperations {
@@ -32,13 +34,8 @@ public interface CouchbaseOperations {
/**
* Save the given object.
*
* When the document already exists (specified by its unique id),
* then it will be overriden. Otherwise it will be created.
*
* <p>
* The object is converted to a JSON representation using an instance of
* {@link CouchbaseConverter}.
* </p>
* <p>When the document already exists (specified by its unique id), then it will be overriden. Otherwise it will be
* created.</p>
*
* @param objectToSave the object to store in the bucket.
*/
@@ -47,8 +44,8 @@ public interface CouchbaseOperations {
/**
* Save a list of objects.
*
* When one of the documents already exists (specified by its unique id),
* then it will be overriden. Otherwise it will be created.
* <p>When one of the documents already exists (specified by its unique id), then it will be overriden. Otherwise it
* will be created.</p>
*
* @param batchToSave the list of objects to store in the bucket.
*/
@@ -57,14 +54,8 @@ public interface CouchbaseOperations {
/**
* Insert the given object.
*
* When the document already exists (specified by its unique id),
* then it will not be overriden. Use the {@link CouchbaseOperations#save}
* method for this.
*
* <p>
* The object is converted to a JSON representation using an instance of
* {@link CouchbaseConverter}.
* </p>
* <p>When the document already exists (specified by its unique id), then it will not be overriden. Use the
* {@link CouchbaseOperations#save} method for this task.</p>
*
* @param objectToSave the object to add to the bucket.
*/
@@ -73,9 +64,8 @@ public interface CouchbaseOperations {
/**
* Insert a list of objects.
*
* When one of the documents already exists (specified by its unique id),
* then it will not be overriden. Use the {@link CouchbaseOperations#save}
* method for this.
* <p>When one of the documents already exists (specified by its unique id), then it will not be overriden. Use the
* {@link CouchbaseOperations#save} method for this.</p>
*
* @param batchToSave the list of objects to add to the bucket.
*/
@@ -84,14 +74,8 @@ public interface CouchbaseOperations {
/**
* Update the given object.
*
* When the document does not exists (specified by its unique id),
* then it will not be created. Use the {@link CouchbaseOperations#save}
* method for this.
*
* <p>
* The object is converted to a JSON representation using an instance of
* {@link CouchbaseConverter}.
* </p>
* <p>When the document does not exist (specified by its unique id) it will not be created. Use the
* {@link CouchbaseOperations#save} method for this.</p>
*
* @param objectToSave the object to add to the bucket.
*/
@@ -100,9 +84,8 @@ public interface CouchbaseOperations {
/**
* Insert a list of objects.
*
* When one of the documents does not exists (specified by its unique id),
* then it will not be created. Use the {@link CouchbaseOperations#save}
* method for this.
* <p>If one of the documents does not exist (specified by its unique id), then it will not be created. Use the
* {@link CouchbaseOperations#save} method for this.</p>
*
* @param batchToSave the list of objects to add to the bucket.
*/
@@ -120,13 +103,11 @@ public interface CouchbaseOperations {
/**
* Query a View for a list of documents of type T.
*
* <p>There is no need to {@link Query#setIncludeDocs(boolean)} explicitely,
* because it will be set to true all the time. It is valid to pass in a
* empty constructed {@link Query} object.</p>
* <p>There is no need to {@link Query#setIncludeDocs(boolean)} explicitely, because it will be set to true all the
* time. It is valid to pass in a empty constructed {@link Query} object.</p>
*
* <p>This method does not work with reduced views, because they by design
* do not contain references to original objects. Use the provided
* {@link #queryView} method for more flexibility and direct access.</p>
* <p>This method does not work with reduced views, because they by design do not contain references to original
* objects. Use the provided {@link #queryView} method for more flexibility and direct access.</p>
*
* @param design the name of the design document.
* @param view the name of the view.
@@ -140,11 +121,11 @@ public interface CouchbaseOperations {
/**
* Query a View with direct access to the {@link ViewResponse}.
*
* <p>This method is available to ease the working with views by still wrapping
* exceptions into the Spring infrastructure.</p>
* <p>This method is available to ease the working with views by still wrapping exceptions into the Spring
* infrastructure.</p>
*
* <p>It is especially needed if you want to run reduced view queries, because
* they can't be mapped onto entities directly.</p>
* <p>It is especially needed if you want to run reduced view queries, because they can't be mapped onto entities
* directly.</p>
*
* @param design the name of the design document.
* @param view the name of the view.
@@ -181,8 +162,7 @@ public interface CouchbaseOperations {
/**
* Executes a BucketCallback translating any exceptions as necessary.
*
* Allows for returning a result object, that is a domain object or a
* collection of domain objects.
* Allows for returning a result object, that is a domain object or a collection of domain objects.
*
* @param action the action to execute in the callback.
* @param <T> the return type.
@@ -191,7 +171,7 @@ public interface CouchbaseOperations {
<T> T execute(BucketCallback<T> action);
/**
* Returns the underlying {@link CouchbaseConverter}
* Returns the underlying {@link CouchbaseConverter}.
* @return
*/
CouchbaseConverter getConverter();

View File

@@ -31,10 +31,7 @@ import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
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.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
import org.springframework.data.couchbase.core.mapping.*;
import org.springframework.data.mapping.context.MappingContext;
import com.couchbase.client.CouchbaseClient;

View File

@@ -19,8 +19,7 @@ package org.springframework.data.couchbase.core;
import org.springframework.dao.TransientDataAccessException;
/**
* Data Access Exception that identifies Operations cancelled while being
* processed.
* Data Access Exception that identifies Operations cancelled while being processed.
*
* @author Michael Nitschinger
*/

View File

@@ -19,8 +19,7 @@ package org.springframework.data.couchbase.core;
import org.springframework.dao.TransientDataAccessException;
/**
* Data Access Exception that identifies Operations interrupted while being
* processed.
* Data Access Exception that identifies Operations interrupted while being processed.
*
* @author Michael Nitschinger
*/

View File

@@ -22,27 +22,50 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityInstantiators;
/**
* An abstract {@link CouchbaseConverter} that provides the basics for the {@link MappingCouchbaseConverter}.
*
* @author Michael Nitschinger
*/
public abstract class AbstractCouchbaseConverter implements CouchbaseConverter,
InitializingBean {
public abstract class AbstractCouchbaseConverter implements CouchbaseConverter, InitializingBean {
/**
* Contains the conversion service.
*/
protected final GenericConversionService conversionService;
/**
* Contains the entity instantiators.
*/
protected EntityInstantiators instantiators = new EntityInstantiators();
/**
* Holds the custom conversions.
*/
protected CustomConversions conversions = new CustomConversions();
public AbstractCouchbaseConverter(
GenericConversionService conversionService) {
/**
* Create a new converter and hand it over the {@link ConversionService}
*
* @param conversionService the conversion service to use.
*/
public AbstractCouchbaseConverter(final GenericConversionService conversionService) {
this.conversionService = conversionService;
}
/**
* Return the conversion service.
*
* @return the conversion service.
*/
public ConversionService getConversionService() {
return conversionService;
}
/**
* Do nothing after the properties set on the bean.
*/
@Override
public void afterPropertiesSet() {
}
}

View File

@@ -23,11 +23,13 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentEntity
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
/**
* Marker interface for the converter, identifying the types to and from that can be converted.
*
* @author Michael Nitschinger
*/
public interface CouchbaseConverter extends
EntityConverter<CouchbasePersistentEntity<?>,
CouchbasePersistentProperty, Object, CouchbaseDocument>,
public interface CouchbaseConverter
extends EntityConverter<CouchbasePersistentEntity<?>,
CouchbasePersistentProperty, Object, CouchbaseDocument>,
CouchbaseWriter<Object, CouchbaseDocument>,
EntityReader<Object, CouchbaseDocument> {
}

View File

@@ -24,24 +24,50 @@ import org.springframework.expression.TypedValue;
import java.util.Map;
/**
* A property accessor for document properties.
*
* @author Michael Nitschinger
*/
public class CouchbaseDocumentPropertyAccessor extends MapAccessor {
static MapAccessor INSTANCE = new CouchbaseDocumentPropertyAccessor();
/**
* Contains the static instance of thi accessor.
*/
static final MapAccessor INSTANCE = new CouchbaseDocumentPropertyAccessor();
/**
* Returns the target classes of the properties.
*
* @return
*/
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class[] {CouchbaseDocument.class};
}
/**
* It can always read from those properties.
*
* @param context the evaluation context.
* @param target the target object.
* @param name the name of the property.
* @return always true.
*/
@Override
public boolean canRead(EvaluationContext context, Object target, String name) {
public boolean canRead(final EvaluationContext context, final Object target, final String name) {
return true;
}
/**
* Read the value from the property.
*
* @param context the evaluation context.
* @param target the target object.
* @param name the name of the property.
* @return the typed value of the content to be read.
*/
@Override
public TypedValue read(EvaluationContext contect, Object target, String name) {
public TypedValue read(final EvaluationContext context, final Object target, final String name) {
Map<String, Object> source = (Map<String, Object>) target;
Object value = source.get(name);

View File

@@ -20,6 +20,8 @@ import org.springframework.data.convert.TypeMapper;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
/**
* Marker interface for the TypeMapper.
*
* @author Michael Nitschinger
*/
public interface CouchbaseTypeMapper extends TypeMapper<CouchbaseDocument> {

View File

@@ -19,9 +19,10 @@ package org.springframework.data.couchbase.core.convert;
import org.springframework.data.convert.EntityWriter;
/**
* Marker interface for the Couchbase {@link EntityWriter}.
*
* @author Michael Nitschinger
*/
public interface CouchbaseWriter<T, ConvertedCouchbaseDocument> extends
EntityWriter<T, ConvertedCouchbaseDocument> {
}

View File

@@ -27,26 +27,42 @@ import java.util.Set;
/**
* Value object to capture custom conversion.
*
* Types that can be mapped directly onto JSON are considered simple ones,
* because they neither need deeper inspection nor nested conversion.
* <p>Types that can be mapped directly onto JSON are considered simple ones, because they neither need deeper
* inspection nor nested conversion.</p>
*
* @author Michael Nitschinger
*/
public class CustomConversions {
/**
* Contains the simple type holder.
*/
private final SimpleTypeHolder simpleTypeHolder;
/**
* Create a new instance with no converters.
*/
CustomConversions() {
this(new ArrayList<Object>());
}
/**
* Create a new instance with a given list of conversers.
* @param converters the list of custom converters.
*/
public CustomConversions(final List<?> converters) {
Assert.notNull(converters);
simpleTypeHolder = new SimpleTypeHolder();
}
public boolean isSimpleType(Class<?> type) {
/**
* Check that the given type is of "simple type".
*
* @param type the type to check.
* @return if its simple type or not.
*/
public boolean isSimpleType(final Class<?> type) {
return simpleTypeHolder.isSimpleType(type);
}

View File

@@ -21,12 +21,22 @@ import org.springframework.data.convert.TypeAliasAccessor;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
/**
* The Couchbase Type Mapper.
*
* @author Michael Nitschinger
*/
public class DefaultCouchbaseTypeMapper extends DefaultTypeMapper<CouchbaseDocument> implements CouchbaseTypeMapper {
/**
* The type key to use if a complex type was identified.
*/
public static final String DEFAULT_TYPE_KEY = "_class";
/**
* Create a new type mapper with the type key.
*
* @param typeKey the typeKey to use.
*/
public DefaultCouchbaseTypeMapper(final String typeKey) {
super(new CouchbaseDocumentTypeAliasAccessor(typeKey));
}

View File

@@ -16,7 +16,6 @@
package org.springframework.data.couchbase.core.convert;
import java.util.*;
import org.springframework.beans.BeansException;
@@ -39,6 +38,10 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* The Couchbase special {@link MappingCouchbaseConverter}.
*
* This converter is responsible for mapping (read and writing) value from and to target formats.
*
* @author Michael Nitschinger
*/
public class MappingCouchbaseConverter extends AbstractCouchbaseConverter

View File

@@ -27,19 +27,31 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* A Jackson JSON Translator.
* A Jackson JSON Translator that implements the {@link TranslationService} contract.
*
* @author Michael Nitschinger
*/
public class JacksonTranslationService implements TranslationService {
/**
* Type holder to help easily identify simple types.
*/
private SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder();
/**
* JSON factory for Jackson.
*/
private JsonFactory factory = new JsonFactory();
/**
* Encode a {@link CouchbaseStorable} to a JSON string.
*
* @param source the source document to encode.
* @return the encoded JSON String.
*/
@Override
public final Object encode(final CouchbaseStorable source) {
OutputStream stream = new ByteArrayOutputStream();
@@ -86,6 +98,13 @@ public class JacksonTranslationService implements TranslationService {
generator.writeEndObject();
}
/**
* Decode a JSON string into the {@link CouchbaseStorable} structure.
*
* @param source the source formatted document.
* @param target the target of the populated data.
* @return the decoded structure.
*/
@Override
public final CouchbaseStorable decode(final Object source, final CouchbaseStorable target) {
try {
@@ -108,6 +127,14 @@ public class JacksonTranslationService implements TranslationService {
return target;
}
/**
* Helper method to decode an object recursively.
*
* @param parser the JSON parser with the content.
* @param target the target where the content should be stored.
* @returns the decoded object.
* @throws IOException
*/
private CouchbaseDocument decodeObject(final JsonParser parser, final CouchbaseDocument target) throws IOException {
JsonToken currentToken = parser.nextToken();
@@ -129,6 +156,14 @@ public class JacksonTranslationService implements TranslationService {
return target;
}
/**
* Helper method to decode an array recusrively.
*
* @param parser the JSON parser with the content.
* @param target the target where the content should be stored.
* @returns the decoded list.
* @throws IOException
*/
private CouchbaseList decodeArray(final JsonParser parser, final CouchbaseList target) throws IOException {
JsonToken currentToken = parser.nextToken();
@@ -147,6 +182,14 @@ public class JacksonTranslationService implements TranslationService {
return target;
}
/**
* Helper method to decode and assign a primitive.
*
* @param token the type of token.
* @param parser the parser with the content.
* @return the decoded primitve.
* @throws IOException
*/
private Object decodePrimitive(final JsonToken token, final JsonParser parser) throws IOException {
switch (token) {
case VALUE_TRUE:

View File

@@ -20,6 +20,8 @@ import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
/**
* Defines a translation service to encode/decode responses into the {@link CouchbaseStorable} format.
*
* @author Michael Nitschinger
*/
public interface TranslationService<T> {

View File

@@ -26,36 +26,49 @@ import org.springframework.data.util.TypeInformation;
import org.springframework.expression.spel.support.StandardEvaluationContext;
/**
* The representation of a persistent entity.
*
* @author Michael Nitschinger
*/
public class BasicCouchbasePersistentEntity<T>
extends BasicPersistentEntity<T, CouchbasePersistentProperty>
public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T, CouchbasePersistentProperty>
implements CouchbasePersistentEntity<T>, ApplicationContextAware {
/**
* Contains the evaluation context.
*/
private final StandardEvaluationContext context;
public BasicCouchbasePersistentEntity(TypeInformation<T> typeInformation) {
/**
* Create a new entity.
* @param typeInformation the type information of the entity.
*/
public BasicCouchbasePersistentEntity(final TypeInformation<T> typeInformation) {
super(typeInformation);
this.context = new StandardEvaluationContext();
context = new StandardEvaluationContext();
}
/**
* Sets the application context.
*
* @param applicationContext the application context.
* @throws BeansException if setting the application context did go wrong.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
}
/**
* Returns the expiration time of the entity.
*
* @return the expiration time.
*/
public int getExpiry() {
org.springframework.data.couchbase.core.mapping.Document annotation =
getType().getAnnotation(org.springframework.data.couchbase.core.mapping.Document.class);
if(annotation == null) {
return 0;
}
return annotation.expiry();
return annotation == null ? 0 : annotation.expiry();
}
}

View File

@@ -26,9 +26,8 @@ import org.springframework.util.StringUtils;
/**
* Implements annotated property representations of a given Field instance.
*
* This object is used to gather information out of properties on objects
* that need to be persisted. For example, it supports overriding of the
* actual property name by providing custom annotations.
* <p>This object is used to gather information out of properties on objects that need to be persisted. For example, it
* supports overriding of the actual property name by providing custom annotations.</p>
*
* @author Michael Nitschinger
*/
@@ -44,9 +43,8 @@ public class BasicCouchbasePersistentProperty
* @param owner the original owner of the property.
* @param simpleTypeHolder the type holder.
*/
public BasicCouchbasePersistentProperty(Field field,
PropertyDescriptor propertyDescriptor, CouchbasePersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
public BasicCouchbasePersistentProperty(final Field field, final PropertyDescriptor propertyDescriptor,
final CouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}

View File

@@ -24,19 +24,15 @@ import java.util.Map;
import java.util.Set;
/**
* A {@link CouchbaseDocument} is an abstract representation of a document stored
* inside Couchbase Server.
* A {@link CouchbaseDocument} is an abstract representation of a document stored inside Couchbase Server.
*
* <p>It acts like a {@link HashMap}, but only allows those types to be written
* that are supported by the underlying storage format, which is currently
* JSON. Note that JSON conversion is not happening here, but performed
* at a different stage based on the payload stored in the
* {@link CouchbaseDocument}.</p>
* <p>It acts like a {@link HashMap}, but only allows those types to be written that are supported by the underlying
* storage format, which is currently JSON. Note that JSON conversion is not happening here, but performed at a
* different stage based on the payload stored in the {@link CouchbaseDocument}.</p>
*
* <p>In addition to the actual content, meta data is also stored. This
* especially refers to the document ID and its expiration time. Note that
* this information is not mandatory, since documents can be nested and
* therefore only the topmost document most likely has an ID.</p>
* <p>In addition to the actual content, meta data is also stored. This especially refers to the document ID and its
* expiration time. Note that this information is not mandatory, since documents can be nested and therefore only the
* topmost document most likely has an ID.</p>
*
* @author Michael Nitschinger
*/
@@ -199,6 +195,13 @@ public class CouchbaseDocument implements CouchbaseStorable {
return totalSize;
}
/**
* Returns the underlying payload.
*
* <p>Note that unlike {@link #export()}, the nested objects are not converted, so the "raw" map is returned.</p>
*
* @return the underlying payload.
*/
public HashMap<String, Object> getPayload() {
return payload;
}
@@ -267,6 +270,11 @@ public class CouchbaseDocument implements CouchbaseStorable {
+ clazz.getCanonicalName() + " can not be stored and must be converted.");
}
/**
* A string representation of expiration, id and payload.
*
* @return the string representation of the object.
*/
@Override
public String toString() {
return "CouchbaseDocument{" +

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013 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.core.mapping;
import org.springframework.data.mapping.model.SimpleTypeHolder;
@@ -5,12 +21,10 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.util.*;
/**
* A {@link CouchbaseList} is an abstract list that represents an array stored
* in a (most of the times JSON) document.
* A {@link CouchbaseList} is an abstract list that represents an array stored in a (most of the times JSON) document.
*
* This {@link CouchbaseList} is part of the potentially nested structure inside
* one or more {@link CouchbaseDocument}s. It can also contain them recursively,
* depending on how the document is modeled.
* <p>This {@link CouchbaseList} is part of the potentially nested structure inside one or more
* {@link CouchbaseDocument}s. It can also contain them recursively, depending on how the document is modeled.</p>
*/
public class CouchbaseList implements CouchbaseStorable {
@@ -24,11 +38,19 @@ public class CouchbaseList implements CouchbaseStorable {
*/
private SimpleTypeHolder simpleTypeHolder;
/**
* Create a new (empty) list.
*/
public CouchbaseList() {
this(new ArrayList<Object>());
}
public CouchbaseList(List<Object> initialPayload) {
/**
* Create a new list with a given payload on construction.
*
* @param initialPayload the initial data to store.
*/
public CouchbaseList(final List<Object> initialPayload) {
payload = initialPayload;
Set<Class<?>> additionalTypes = new HashSet<Class<?>>();
@@ -37,14 +59,26 @@ public class CouchbaseList implements CouchbaseStorable {
simpleTypeHolder = new SimpleTypeHolder(additionalTypes, true);
}
public final CouchbaseList put(Object value) {
/**
* Add content to the underlying list.
*
* @param value the value to be added.
* @return the {@link CouchbaseList} object for chaining purposes.
*/
public final CouchbaseList put(final Object value) {
verifyValueType(value.getClass());
payload.add(value);
return this;
}
public final Object get(int index) {
/**
* Return the stored element at the given index.
*
* @param index the index where the document is located.
* @return the found object (or null if nothing found).
*/
public final Object get(final int index) {
return payload.get(index);
}
@@ -117,6 +151,11 @@ public class CouchbaseList implements CouchbaseStorable {
return payload.contains(value);
}
/**
* Checks if the underlying payload is empty or not.
*
* @return whether the underlying payload is empty or not.
*/
public final boolean isEmpty() {
return payload.isEmpty();
}
@@ -139,6 +178,11 @@ public class CouchbaseList implements CouchbaseStorable {
+ clazz.getCanonicalName() + "can not be stored and must be converted.");
}
/**
* A string reprensation of the payload.
*
* @return the underlying payload as a string representation for easier debugging.
*/
@Override
public String toString() {
return "CouchbaseList{" +

View File

@@ -14,47 +14,72 @@
* limitations under the License.
*/
package org.springframework.data.couchbase.core;
package org.springframework.data.couchbase.core.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.couchbase.core.mapping.BasicCouchbasePersistentEntity;
import org.springframework.data.couchbase.core.mapping.BasicCouchbasePersistentProperty;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
/**
* Default implementation of a {@link org.springframework.data.mapping.context.MappingContext} for Couchbase using
* {@link BasicCouchbasePersistentEntity} and {@link BasicCouchbasePersistentProperty} as primary abstractions.
*
* @author Michael Nitschinger
*/
public class CouchbaseMappingContext
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
implements ApplicationContextAware {
/**
* Contains the application context to configure the application.
*/
private ApplicationContext context;
/**
* Creates a concrete entity based out of the type information passed.
*
* @param typeInformation type information of the entity to create.
* @param <T> the type for the corresponding type information.
* @return the constructed entity.
*/
@Override
protected <T> BasicCouchbasePersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
protected <T> BasicCouchbasePersistentEntity<?> createPersistentEntity(final TypeInformation<T> typeInformation) {
BasicCouchbasePersistentEntity<T> entity = new BasicCouchbasePersistentEntity<T>(typeInformation);
if(context != null) {
if (context != null) {
entity.setApplicationContext(context);
}
return entity;
}
/**
* Creates a concrete property based on the field information and entity.
*
* @param field the reflection on the field to be used as a property.
* @param descriptor the property descriptor.
* @param owner the entity which owns the property.
* @param simpleTypeHolder the type holder.
* @return the constructed property.
*/
@Override
protected CouchbasePersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor, BasicCouchbasePersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
protected CouchbasePersistentProperty createPersistentProperty(final Field field, final PropertyDescriptor descriptor,
final BasicCouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder) {
return new BasicCouchbasePersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
/**
* Sets (or overrides) the current application context.
*
* @param applicationContext the application context to be assigned.
* @throws BeansException if the context can not be set properly.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}

View File

@@ -19,15 +19,18 @@ package org.springframework.data.couchbase.core.mapping;
import org.springframework.data.mapping.PersistentEntity;
/**
* Represents an entity that can be persisted which contains 0 or more properties.
*
* @author Michael Nitschinger
*/
public interface CouchbasePersistentEntity<T> extends
PersistentEntity<T, CouchbasePersistentProperty> {
/**
* Returns the expiry time for the document.
*
* @return
*/
/**
* Returns the expiry time for the document.
*
* @return the expiration time.
*/
int getExpiry();
}

View File

@@ -19,16 +19,16 @@ package org.springframework.data.couchbase.core.mapping;
import org.springframework.data.mapping.PersistentProperty;
/**
* Represents a property part of an entity that needs to be persisted.
*
* @author Michael Nitschinger
*/
public interface CouchbasePersistentProperty extends
PersistentProperty<CouchbasePersistentProperty> {
public interface CouchbasePersistentProperty extends PersistentProperty<CouchbasePersistentProperty> {
/**
* Returns the field name of the property.
*
* The field name can be different from the actual property name by using a
* custom annotation.
* The field name can be different from the actual property name by using a custom annotation.
*/
String getFieldName();

View File

@@ -1,5 +1,11 @@
package org.springframework.data.couchbase.core.mapping;
/**
* Marker Interface to identify either a {@link CouchbaseDocument} or a {@link CouchbaseList}.
*
* This interface will be extended in the future to refactor the needed infrastructure into the common interface.
*
* @author Michael Nitschinger
*/
public interface CouchbaseStorable {
}

View File

@@ -21,8 +21,7 @@ import org.springframework.data.repository.CrudRepository;
import java.io.Serializable;
/**
* Couchbase specific {@link org.springframework.data.repository.Repository}
* interface.
* Couchbase specific {@link org.springframework.data.repository.Repository} interface.
*
* @author Michael Nitschinger
*/

View File

@@ -42,13 +42,13 @@ public class CouchbaseRepositoryConfigurationExtension extends RepositoryConfigu
}
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {
public void postProcess(final BeanDefinitionBuilder builder, final XmlRepositoryConfigurationSource config) {
Element element = config.getElement();
ParsingUtils.setPropertyReference(builder, element, COUCHBASE_TEMPLATE_REF, "couchbaseOperations");
}
@Override
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) {
public void postProcess(final BeanDefinitionBuilder builder, final AnnotationRepositoryConfigurationSource config) {
AnnotationAttributes attributes = config.getAttributes();
builder.addPropertyReference("couchbaseOperations", attributes.getString("couchbaseTemplateRef"));
}

View File

@@ -21,6 +21,8 @@ import org.springframework.data.repository.core.EntityInformation;
import java.io.Serializable;
/**
* Marker interface for the Couchbase Entity Information.
*
* @author Michael Nitschinger
*/
public interface CouchbaseEntityInformation<T, ID extends Serializable> extends EntityInformation<T, ID> {

View File

@@ -29,43 +29,75 @@ import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Factory to create {@link CouchbaseRepository} instances.
* Factory to create {@link SimpleCouchbaseRepository} instances.
*
* @author Michael Nitschinger
*/
public class CouchbaseRepositoryFactory extends RepositoryFactorySupport {
/**
* Holds the reference to the template.
*/
private final CouchbaseOperations couchbaseOperations;
private final MappingContext<? extends CouchbasePersistentEntity<?>,
CouchbasePersistentProperty> mappingContext;
/**
* Holds the mapping context.
*/
private final MappingContext<? extends CouchbasePersistentEntity<?>, CouchbasePersistentProperty> mappingContext;
/**
* Create a new factory.
*
* @param couchbaseOperations the template for the underlying actions.
*/
public CouchbaseRepositoryFactory(final CouchbaseOperations couchbaseOperations) {
Assert.notNull(couchbaseOperations);
this.couchbaseOperations = couchbaseOperations;
mappingContext = couchbaseOperations.getConverter().getMappingContext();
}
/**
* Returns entity information based on the domain class.
*
* @param domainClass the class for the entity.
* @param <T> the value type
* @param <ID> the id type.
* @return entity information for that domain class.
*/
@Override
public <T, ID extends Serializable> CouchbaseEntityInformation<T, ID>
getEntityInformation(Class<T> domainClass) {
getEntityInformation(final Class<T> domainClass) {
CouchbasePersistentEntity<?> entity = mappingContext.getPersistentEntity(domainClass);
if(entity == null) {
if (entity == null) {
throw new MappingException(String.format("Could not lookup mapping metadata for domain class %s!",
domainClass.getName()));
}
return new MappingCouchbaseEntityInformation<T, ID>((CouchbasePersistentEntity<T>) entity);
}
/**
* Returns a new Repository based on the metadata.
*
* @param metadata the repository metadata.
* @return a new created repository.
*/
@Override
protected Object getTargetRepository(RepositoryMetadata metadata) {
protected Object getTargetRepository(final RepositoryMetadata metadata) {
CouchbaseEntityInformation<?, Serializable> entityInformation =
getEntityInformation(metadata.getDomainType());
return new SimpleCouchbaseRepository(entityInformation, couchbaseOperations);
}
/**
* The base class for this repository.
*
* @param repositoryMetadata metadata for the repository.
* @return the base class.
*/
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata repositoryMetadata) {
protected Class<?> getRepositoryBaseClass(final RepositoryMetadata repositoryMetadata) {
return SimpleCouchbaseRepository.class;
}
}

View File

@@ -25,27 +25,51 @@ import org.springframework.util.Assert;
import java.io.Serializable;
/**
* The factory bean to create repositories.
*
* @author Michael Nitschinger
*/
public class CouchbaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
RepositoryFactoryBeanSupport<T, S, ID> {
/**
* Contains the reference to the template.
*/
private CouchbaseOperations operations;
public void setCouchbaseOperations(CouchbaseOperations operations) {
/**
* Set the template reference.
*
* @param operations the reference to the operations template.
*/
public void setCouchbaseOperations(final CouchbaseOperations operations) {
this.operations = operations;
setMappingContext(operations.getConverter().getMappingContext());
}
/**
* Returns a factory instance.
*
* @return the factory instance.
*/
@Override
protected RepositoryFactorySupport createRepositoryFactory() {
return getFactoryInstance(operations);
}
private RepositoryFactorySupport getFactoryInstance(CouchbaseOperations operations) {
/**
* Get the factory instance for the operations.
*
* @param operations the reference to the template.
* @return the factory instance.
*/
private RepositoryFactorySupport getFactoryInstance(final CouchbaseOperations operations) {
return new CouchbaseRepositoryFactory(operations);
}
/**
* Make sure that the template is set and not null.
*/
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();

View File

@@ -25,24 +25,40 @@ import org.springframework.data.repository.core.support.AbstractEntityInformatio
import java.io.Serializable;
/**
* Entity Information container.
*
* @author Michael Nitschinger
*/
public class MappingCouchbaseEntityInformation<T, ID extends Serializable>
extends AbstractEntityInformation<T, ID>
implements CouchbaseEntityInformation<T, ID> {
/**
* Contains the entity metadata.
*/
private final CouchbasePersistentEntity<T> entityMetadata;
public MappingCouchbaseEntityInformation(CouchbasePersistentEntity<T> entity) {
/**
* Create a new Infomration container.
*
* @param entity the entity of the container.
*/
public MappingCouchbaseEntityInformation(final CouchbasePersistentEntity<T> entity) {
super(entity.getType());
entityMetadata = entity;
}
/**
* Returns the ID of the entity.
*
* @param entity the entity from where to extract the ID from.
* @return the id of the entity.
*/
@Override
public ID getId(T entity) {
CouchbasePersistentProperty idProperty = entityMetadata.getIdProperty();
if(idProperty == null) {
if (idProperty == null) {
return null;
}
@@ -53,6 +69,11 @@ public class MappingCouchbaseEntityInformation<T, ID extends Serializable>
}
}
/**
* Returns the ID type.
*
* @return the ID type.
*/
@Override
public Class<ID> getIdType() {
return (Class<ID>) entityMetadata.getIdProperty().getType();

View File

@@ -39,11 +39,25 @@ import java.util.List;
*/
public class SimpleCouchbaseRepository<T, ID extends Serializable> implements CouchbaseRepository<T, ID> {
/**
* Holds the reference to the {@link org.springframework.data.couchbase.core.CouchbaseTemplate}.
*/
private final CouchbaseOperations couchbaseOperations;
/**
* Contains information about the entity being used in this repository.
*/
private final CouchbaseEntityInformation<T, String> entityInformation;
public SimpleCouchbaseRepository(CouchbaseEntityInformation<T, String> metadata, CouchbaseOperations couchbaseOperations) {
/**
* Create a new Repository.
*
* @param metadata the Metadata for the entity.
* @param couchbaseOperations the reference to the template used.
*/
public SimpleCouchbaseRepository(final CouchbaseEntityInformation<T, String> metadata,
final CouchbaseOperations couchbaseOperations) {
Assert.notNull(couchbaseOperations);
Assert.notNull(metadata);
@@ -156,10 +170,20 @@ public class SimpleCouchbaseRepository<T, ID extends Serializable> implements Co
}
}
/**
* Returns the underlying operation template.
*
* @return the underlying template.
*/
protected CouchbaseOperations getCouchbaseOperations() {
return couchbaseOperations;
}
/**
* Returns the information for the underlying template.
*
* @return the underlying entity information.
*/
protected CouchbaseEntityInformation<T, String> getEntityInformation() {
return entityInformation;
}