diff --git a/README.md b/README.md
index cec96fc7..b068acb1 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
+# Spring Data Couchbase - v2
+This branch is a work in progress, it will contain the do-over of the `Spring-Data Couchbase` connector
+for the `Couchbase Java SDK 2.x` generation.
+
+Below is the v1 README as of `75bce39`:
+
# Spring Data Couchbase
The primary goal of the [Spring Data](http://www.springsource.org/spring-data) project is to make it easier to build
diff --git a/pom.xml b/pom.xml
index 9739b8ed..46ca3124 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,155 +1,164 @@
-
+
- 4.0.0
+ 4.0.0
- org.springframework.data
- spring-data-couchbase
- 1.4.0.BUILD-SNAPSHOT
+ org.springframework.data
+ spring-data-couchbase
+ 2.0.0.BUILD-SNAPSHOT
- Spring Data Couchbase
- Spring Data integration for Couchbase
- https://github.com/SpringSource/spring-data-couchbase
+ Spring Data Couchbase
+ Spring Data integration for Couchbase
+ https://github.com/SpringSource/spring-data-couchbase
-
- org.springframework.data.build
- spring-data-parent
- 1.7.0.BUILD-SNAPSHOT
-
+
+ org.springframework.data.build
+ spring-data-parent
+ 1.7.0.BUILD-SNAPSHOT
+
-
+
- DATACOUCH
+ DATACOUCH
- 1.4.7
- 2.3.2
- 1.11.0.BUILD-SNAPSHOT
- 1.0.0.GA
-
+ 2.2.0-dp
+ 2.3.2
+ 1.11.0.BUILD-SNAPSHOT
+ 1.0.0.GA
+
-
+
-
- org.springframework
- spring-context
-
-
- org.springframework
- spring-web
-
-
- org.springframework
- spring-tx
-
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-web
+
+
+ org.springframework
+ spring-tx
+
-
- ${project.groupId}
- spring-data-commons
- ${springdata.commons}
-
+
+ ${project.groupId}
+ spring-data-commons
+ ${springdata.commons}
+
-
- com.couchbase.client
- couchbase-client
- ${couchbase}
-
+
+ com.couchbase.client
+ java-client
+ ${couchbase}
+
-
- org.springframework
- spring-test
- ${spring}
- test
-
+
+ org.springframework
+ spring-test
+ ${spring}
+ test
+
-
- org.hibernate
- hibernate-validator
- 4.2.0.Final
- test
-
+
+ org.hibernate
+ hibernate-validator
+ 4.2.0.Final
+ test
+
-
- org.apache.httpcomponents
- httpclient
- 4.3.3
- test
-
+
+ org.apache.httpcomponents
+ httpclient
+ 4.3.3
+ test
+
-
- com.fasterxml.jackson.core
- jackson-databind
- ${jackson}
-
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson}
+
-
- joda-time
- joda-time
- ${jodatime}
- true
-
+
+ joda-time
+ joda-time
+ ${jodatime}
+ true
+
-
-
- javax.validation
- validation-api
- ${validation}
- true
-
+
+
+ javax.validation
+ validation-api
+ ${validation}
+ true
+
-
-
- javax.enterprise
- cdi-api
- ${cdi}
- provided
- true
-
+
+
+ javax.enterprise
+ cdi-api
+ ${cdi}
+ provided
+ true
+
-
- org.apache.openwebbeans.test
- cditest-owb
- ${webbeans}
- test
-
+
+ org.apache.openwebbeans.test
+ cditest-owb
+ ${webbeans}
+ test
+
-
- javax.servlet
- servlet-api
- 3.0-alpha-1
- test
-
+
+ javax.servlet
+ servlet-api
+ 3.0-alpha-1
+ test
+
-
+
-
-
- spring-libs-snapshot
- https://repo.spring.io/libs-snapshot
-
-
+
+
+ spring-libs-snapshot
+ https://repo.spring.io/libs-snapshot
+
+
+ couchbase
+ couchbase repo
+ http://files.couchbase.com/maven2
+
+ false
+
+
+
-
-
- spring-plugins-release
- https://repo.spring.io/plugins-release
-
-
+
+
+ spring-plugins-release
+ https://repo.spring.io/plugins-release
+
+
-
-
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
- org.codehaus.mojo
- wagon-maven-plugin
-
-
- org.asciidoctor
- asciidoctor-maven-plugin
-
-
-
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ org.codehaus.mojo
+ wagon-maven-plugin
+
+
+ org.asciidoctor
+ asciidoctor-maven-plugin
+
+
+
-
+
\ No newline at end of file
diff --git a/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java
new file mode 100644
index 00000000..f9d8e863
--- /dev/null
+++ b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java
@@ -0,0 +1,67 @@
+package org.springframework.data.couchbase;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
+import org.springframework.data.couchbase.core.CouchbaseTemplate;
+import org.springframework.data.couchbase.core.WriteResultChecking;
+
+@Configuration
+public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfiguration {
+
+ @Autowired
+ private Environment springEnv;
+
+ @Bean
+ public String couchbaseAdminUser() {
+ return springEnv.getProperty("couchbase.adminUser", "Administrator");
+ }
+
+ @Bean
+ public String couchbaseAdminPassword() {
+ return springEnv.getProperty("couchbase.adminUser", "password");
+ }
+
+ @Override
+ protected List getBootstrapHosts() {
+ return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1"));
+ }
+
+ @Override
+ protected String getBucketName() {
+ return springEnv.getProperty("couchbase.bucket", "default");
+ }
+
+ @Override
+ protected String getBucketPassword() {
+ return springEnv.getProperty("couchbase.password", "");
+ }
+
+
+ //TODO maybe create the bucket if doesn't exist
+
+ @Override
+ protected CouchbaseEnvironment getEnvironment() {
+ return DefaultCouchbaseEnvironment.builder()
+ .connectTimeout(10000)
+ .kvTimeout(10000)
+ .queryTimeout(10000)
+ .viewTimeout(10000)
+ .build();
+ }
+
+ @Override
+ public CouchbaseTemplate couchbaseTemplate() throws Exception {
+ CouchbaseTemplate template = super.couchbaseTemplate();
+ template.setWriteResultChecking(WriteResultChecking.LOG);
+ return template;
+ }
+}
diff --git a/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java b/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java
new file mode 100644
index 00000000..c235f80a
--- /dev/null
+++ b/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java
@@ -0,0 +1,75 @@
+/*
+ * 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.config;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionReader;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.core.io.ClassPathResource;
+
+/**
+ * @author Michael Nitschinger
+ */
+public class CouchbaseTemplateParserIntegrationTests {
+
+ DefaultListableBeanFactory factory;
+ BeanDefinitionReader reader;
+
+ @Before
+ public void setUp() {
+ factory = new DefaultListableBeanFactory();
+ reader = new XmlBeanDefinitionReader(factory);
+ }
+
+ @Test
+ public void readsCouchbaseTemplateAttributesCorrectly() {
+ reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-bean.xml"));
+
+ BeanDefinition definition = factory.getBeanDefinition("couchbaseTemplate");
+ assertEquals(1, definition.getConstructorArgumentValues().getArgumentCount());
+
+ factory.getBean("couchbaseTemplate");
+ }
+
+ @Test
+ public void readsCouchbaseTemplateWithTranslationServiceAttributesCorrectly() {
+ reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-with-translation-service-bean.xml"));
+
+ BeanDefinition definition = factory.getBeanDefinition("couchbaseTemplate");
+ assertEquals(2, definition.getConstructorArgumentValues().getArgumentCount());
+
+ factory.getBean("couchbaseTemplate");
+ }
+
+ /**
+ * Test case for DATACOUCH-47.
+ */
+ @Test
+ public void allowsMultipleBuckets() {
+ reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-multi-bucket-bean.xml"));
+
+ factory.getBean("cb-template-first");
+ factory.getBean("cb-template-second");
+ }
+
+}
diff --git a/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java
new file mode 100644
index 00000000..a7db9bf7
--- /dev/null
+++ b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java
@@ -0,0 +1,643 @@
+/*
+ * 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;
+
+import static com.couchbase.client.java.query.Select.select;
+import static com.couchbase.client.java.query.dsl.Expression.i;
+import static com.couchbase.client.java.query.dsl.Expression.s;
+import static com.couchbase.client.java.query.dsl.Expression.x;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.document.RawJsonDocument;
+import com.couchbase.client.java.error.DocumentDoesNotExistException;
+import com.couchbase.client.java.query.Query;
+import com.couchbase.client.java.query.QueryResult;
+import com.couchbase.client.java.query.dsl.Expression;
+import com.couchbase.client.java.view.Stale;
+import com.couchbase.client.java.view.ViewQuery;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.OptimisticLockingFailureException;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.Version;
+import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
+import org.springframework.data.couchbase.core.mapping.Document;
+import org.springframework.data.couchbase.core.mapping.Field;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @author Michael Nitschinger
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
+@TestExecutionListeners(CouchbaseTemplateViewListener.class)
+public class CouchbaseTemplateTests {
+
+ @Autowired
+ private Bucket client;
+
+ @Autowired
+ private CouchbaseTemplate template;
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private void removeIfExist(String key) {
+ try {
+ client.remove(key);
+ }
+ catch (DocumentDoesNotExistException e) {
+ //ignore
+ }
+ }
+
+ @Test
+ public void saveSimpleEntityCorrectly() throws Exception {
+ String id = "beers:awesome-stout";
+ String name = "The Awesome Stout";
+ boolean active = false;
+ Beer beer = new Beer(id).setName(name).setActive(active);
+
+ template.save(beer);
+ RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
+ assertNotNull(resultDoc);
+ String result = resultDoc.content();
+ assertNotNull(result);
+ Map resultConv = MAPPER.readValue(result, new TypeReference
*
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
- * entities.
+ * entities.
*/
protected String getMappingBasePackage() {
return getClass().getPackage().getName();
@@ -225,19 +239,4 @@ public abstract class AbstractCouchbaseConfiguration {
protected FieldNamingStrategy fieldNamingStrategy() {
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE;
}
-
- /**
- * Converts the given list of hostnames into parsable URIs.
- *
- * @param hosts the list of hosts to convert.
- * @return the converted URIs.
- */
- protected static List bootstrapUris(List hosts) throws URISyntaxException {
- List uris = new ArrayList();
- for (String host : hosts) {
- uris.add(new URI("http://" + host + ":8091/pools"));
- }
- return uris;
- }
-
}
diff --git a/src/main/java/org/springframework/data/couchbase/config/BeanNames.java b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java
index 4e43ec8d..05add28b 100644
--- a/src/main/java/org/springframework/data/couchbase/config/BeanNames.java
+++ b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -20,22 +20,32 @@ 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
+ * @author Simon Baslé
*/
-public class BeanNames {
+class BeanNames {
/**
- * Refers to the "" bean.
+ * Refers to the "<couchbase:env />" bean.
*/
- static final String COUCHBASE = "couchbase";
+ static final String COUCHBASE_ENV = "couchbaseEnv";
+ /**
+ * Refers to the "<couchbase:cluster />" bean.
+ */
+ static final String COUCHBASE_CLUSTER = "couchbaseCluster";
/**
- * Refers to the "" bean.
+ * Refers to the "<couchbase:bucket />" bean.
+ */
+ static final String COUCHBASE_BUCKET = "couchbaseBucket";
+
+ /**
+ * Refers to the "<couchbase:template />" bean.
*/
static final String COUCHBASE_TEMPLATE = "couchbaseTemplate";
/**
- * Refers to the "" bean
+ * Refers to the "<couchbase:translation-service />" bean
*/
- static final String TRANSLATION_SERVICE = "translationService";
+ static final String TRANSLATION_SERVICE = "couchbaseTranslationService";
}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java
new file mode 100644
index 00000000..a4dd771e
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java
@@ -0,0 +1,78 @@
+/*
+ * 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.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseBucket;
+
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
+import org.springframework.data.couchbase.core.CouchbaseExceptionTranslator;
+
+/**
+ * The Factory Bean to help {@link CouchbaseBucketParser} constructing a {@link Bucket} from a given
+ * {@link Cluster} reference.
+ *
+ * @author Simon Baslé
+ */
+public class CouchbaseBucketFactoryBean extends AbstractFactoryBean implements PersistenceExceptionTranslator {
+
+ private final Cluster cluster;
+ private final String bucketName;
+ private final String bucketPassword;
+
+ private final PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
+
+ public CouchbaseBucketFactoryBean(Cluster cluster) {
+ this(cluster, null, null);
+ }
+
+ public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName) {
+ this(cluster, bucketName, null);
+ }
+
+ public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName, String bucketPassword) {
+ this.cluster = cluster;
+ this.bucketName = bucketName;
+ this.bucketPassword = bucketPassword;
+ }
+
+ @Override
+ public Class> getObjectType() {
+ return CouchbaseBucket.class;
+ }
+
+ @Override
+ protected Bucket createInstance() throws Exception {
+ if (bucketName == null) {
+ return cluster.openBucket();
+ }
+ else if (bucketPassword == null) {
+ return cluster.openBucket(bucketName);
+ }
+ else {
+ return cluster.openBucket(bucketName, bucketPassword);
+ }
+ }
+
+ @Override
+ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
+ return exceptionTranslator.translateExceptionIfPossible(ex);
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java
new file mode 100644
index 00000000..431b2456
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java
@@ -0,0 +1,103 @@
+/*
+ * 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.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * The parser for XML definition of a {@link Bucket}, to be constructed from a {@link Cluster} reference.
+ * If no reference is given, the default reference {@value BeanNames#COUCHBASE_CLUSTER} is used.
+ *
+ * See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}.
+ *
+ * @author Simon Baslé
+ */
+public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser {
+
+ /**
+ * The cluster-ref attribute in a bucket definition defines the cluster to build from.
+ */
+ public static final String CLUSTER_REF_ATTR = "cluster-ref";
+
+ /**
+ * The bucketName attribute in a bucket definition defines the name of the bucket to open.
+ */
+ public static final String BUCKETNAME_ATTR = "bucketName";
+
+ /**
+ * The bucketPassword attribute in a bucket definition defines the password of the bucket to open.
+ */
+ public static final String BUCKETPASSWORD_ATTR = "bucketPassword";
+
+ /**
+ * 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_BUCKET;
+ }
+
+ /**
+ * 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 CouchbaseBucketFactoryBean.class;
+ }
+
+ /**
+ * Parse the bean definition and build up the bean.
+ *
+ * @param element the XML element which contains the attributes.
+ * @param builder the builder which builds the bean.
+ */
+ @Override
+ protected void doParse(final Element element, final BeanDefinitionBuilder builder) {
+ String clusterRef = element.getAttribute(CLUSTER_REF_ATTR);
+ if (!StringUtils.hasText(clusterRef)) {
+ clusterRef = BeanNames.COUCHBASE_CLUSTER;
+ }
+ builder.addConstructorArgReference(clusterRef);
+
+ String bucketName = element.getAttribute(BUCKETNAME_ATTR);
+ if (StringUtils.hasText(bucketName)) {
+ builder.addConstructorArgValue(bucketName);
+ }
+
+ String bucketPassword = element.getAttribute(BUCKETPASSWORD_ATTR);
+ if (StringUtils.hasText(bucketPassword)) {
+ builder.addConstructorArgValue(bucketPassword);
+ }
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java
new file mode 100644
index 00000000..1e78bf08
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java
@@ -0,0 +1,156 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+
+/**
+ * The XML parser for a {@link Cluster} definition.
+ *
+ * Such a definition can be tuned by either referencing a {@link CouchbaseEnvironment} via
+ * the {@value #CLUSTER_ENVIRONMENT_REF} attribute or define a custom environment inline via
+ * the <{@value #CLUSTER_ENVIRONMENT_TAG}> tag (not recommended, environments should be
+ * shared as possible). If no environment reference or inline description is provided, the
+ * default environment reference {@value BeanNames#COUCHBASE_ENV} is used.
+ *
+ * To bootstrap the connection, one can provide IPs or hostnames of nodes to connect to
+ * via 1 or more <{@value #CLUSTER_NODE_TAG}> tags.
+ *
+ * @author Simon Baslé
+ */
+public class CouchbaseClusterParser extends AbstractSingleBeanDefinitionParser {
+
+ /**
+ * The <node> elements in a cluster definition define the bootstrap hosts to use
+ */
+ public static final String CLUSTER_NODE_TAG = "node";
+
+ /**
+ * The unique <env> element in a cluster definition define the environment customizations.
+ *
+ * @see CouchbaseEnvironmentParser CouchbaseEnvironmentParser for the possible fields.
+ * @see #CLUSTER_ENVIRONMENT_REF CLUSTER_ENVIRONMENT_REF as an alternative (giving a reference to
+ * an env instead of inline description, lower precedence)
+ */
+ public static final String CLUSTER_ENVIRONMENT_TAG = "env";
+
+ /**
+ * The <env-ref> attribute allows to use a reference to an {@link CouchbaseEnvironment} to
+ * tune the connection.
+ *
+ * @see #CLUSTER_ENVIRONMENT_TAG CLUSTER_ENVIRONMENT_TAG for an inline alternative
+ * (which takes priority over this reference)
+ */
+ public static final String CLUSTER_ENVIRONMENT_REF = "env-ref";
+
+ /**
+ * 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_CLUSTER;
+ }
+
+ /**
+ * 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 CouchbaseCluster.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) {
+ bean.setFactoryMethod("create");
+ bean.setDestroyMethodName("disconnect");
+
+ parseEnvironment(bean, element);
+
+ List nodes = DomUtils.getChildElementsByTagName(element, CLUSTER_NODE_TAG);
+ if (nodes != null && nodes.size() > 0) {
+ List bootstrapUrls = new ArrayList(nodes.size());
+ for (int i = 0; i < nodes.size(); i++) {
+ bootstrapUrls.add(nodes.get(i).getTextContent());
+ }
+ bean.addConstructorArgValue(bootstrapUrls);
+ }
+ }
+
+ /**
+ * @return true if a custom environment was parsed and injected (either reference or inline), false if
+ * the default environment reference was used.
+ */
+ protected boolean parseEnvironment(BeanDefinitionBuilder clusterBuilder, Element clusterElement) {
+ //any inline environment description would take precedence over a reference
+ Element envElement = DomUtils.getChildElementByTagName(clusterElement, CLUSTER_ENVIRONMENT_TAG);
+ if (envElement != null && envElement.hasAttributes()) {
+ injectEnvElement(clusterBuilder, envElement);
+ return true;
+ }
+
+ //secondly try to see if an env has been referenced
+ String envRef = clusterElement.getAttribute(CLUSTER_ENVIRONMENT_REF);
+ if (StringUtils.hasText(envRef)) {
+ injectEnvReference(clusterBuilder, envRef);
+ return true;
+ }
+
+ //if no custom value provided, consider it a reference to the default bean for Couchbase Environment
+ injectEnvReference(clusterBuilder, BeanNames.COUCHBASE_ENV);
+ return false;
+ }
+
+ protected void injectEnvElement(BeanDefinitionBuilder clusterBuilder, Element envElement) {
+ BeanDefinitionBuilder envDefinitionBuilder = BeanDefinitionBuilder
+ .genericBeanDefinition(CouchbaseEnvironmentFactoryBean.class);
+ new CouchbaseEnvironmentParser().doParse(envElement, envDefinitionBuilder);
+
+ clusterBuilder.addConstructorArgValue(envDefinitionBuilder.getBeanDefinition());
+ }
+
+ protected void injectEnvReference(BeanDefinitionBuilder clusterBuilder, String envRef) {
+ clusterBuilder.addConstructorArgReference(envRef);
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java
new file mode 100644
index 00000000..e452b50e
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java
@@ -0,0 +1,259 @@
+/*
+ * 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.retry.BestEffortRetryStrategy;
+import com.couchbase.client.core.retry.FailFastRetryStrategy;
+import com.couchbase.client.core.retry.RetryStrategy;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+/**
+ * Factory Bean to help create a CouchbaseEnvironment (by offering setters for supported tuning methods).
+ *
+ * @author Simon Baslé
+ */
+/*package*/ class CouchbaseEnvironmentFactoryBean extends AbstractFactoryBean {
+
+ private static final CouchbaseEnvironment DEFAULT_ENV = DefaultCouchbaseEnvironment.create();
+ public static final String RETRYSTRATEGY_FAILFAST = "FailFast";
+ public static final String RETRYSTRATEGY_BESTEFFORT = "BestEffort";
+
+ private long managementTimeout = DEFAULT_ENV.managementTimeout();
+ private long queryTimeout = DEFAULT_ENV.queryTimeout();
+ private long viewTimeout = DEFAULT_ENV.viewTimeout();
+ private long kvTimeout = DEFAULT_ENV.kvTimeout();
+ private long connectTimeout = DEFAULT_ENV.connectTimeout();
+ private long disconnectTimeout = DEFAULT_ENV.disconnectTimeout();
+ private boolean dnsSrvEnabled = DEFAULT_ENV.dnsSrvEnabled();
+
+ private boolean dcpEnabled = DEFAULT_ENV.dcpEnabled();
+ private boolean sslEnabled = DEFAULT_ENV.sslEnabled();
+ private String sslKeystoreFile = DEFAULT_ENV.sslKeystoreFile();
+ private String sslKeystorePassword = DEFAULT_ENV.sslKeystorePassword();
+ private boolean queryEnabled = DEFAULT_ENV.queryEnabled();
+ private int queryPort = DEFAULT_ENV.queryPort();
+ private boolean bootstrapHttpEnabled = DEFAULT_ENV.bootstrapHttpEnabled();
+ private boolean bootstrapCarrierEnabled = DEFAULT_ENV.bootstrapCarrierEnabled();
+ private int bootstrapHttpDirectPort = DEFAULT_ENV.bootstrapHttpDirectPort();
+ private int bootstrapHttpSslPort = DEFAULT_ENV.bootstrapHttpSslPort();
+ private int bootstrapCarrierDirectPort = DEFAULT_ENV.bootstrapCarrierDirectPort();
+ private int bootstrapCarrierSslPort = DEFAULT_ENV.bootstrapCarrierSslPort();
+ private int ioPoolSize = DEFAULT_ENV.ioPoolSize();
+ private int computationPoolSize = DEFAULT_ENV.computationPoolSize();
+ private int responseBufferSize = DEFAULT_ENV.responseBufferSize();
+ private int requestBufferSize = DEFAULT_ENV.requestBufferSize();
+ private int kvEndpoints = DEFAULT_ENV.kvEndpoints();
+ private int viewEndpoints = DEFAULT_ENV.viewEndpoints();
+ private int queryEndpoints = DEFAULT_ENV.queryEndpoints();
+ private RetryStrategy retryStrategy = DEFAULT_ENV.retryStrategy();
+ private long maxRequestLifetime = DEFAULT_ENV.maxRequestLifetime();
+ private long keepAliveInterval = DEFAULT_ENV.keepAliveInterval();
+ private long autoreleaseAfter = DEFAULT_ENV.autoreleaseAfter();
+ private boolean bufferPoolingEnabled = DEFAULT_ENV.bufferPoolingEnabled();
+
+ //These are tunings that are not practical to be exposed in a xml configuration
+ //or not supposed to be modified that easily:
+// observeIntervalDelay
+// reconnectDelay
+// retryDelay
+// userAgent
+// packageNameAndVersion
+// ioPool
+// scheduler
+// eventBus
+
+ @Override
+ public Class> getObjectType() {
+ return DefaultCouchbaseEnvironment.class;
+ }
+
+ @Override
+ protected CouchbaseEnvironment createInstance() throws Exception {
+ return DefaultCouchbaseEnvironment.builder()
+ .managementTimeout(managementTimeout)
+ .queryTimeout(queryTimeout)
+ .viewTimeout(viewTimeout)
+ .kvTimeout(kvTimeout)
+ .connectTimeout(connectTimeout)
+ .disconnectTimeout(disconnectTimeout)
+ .dnsSrvEnabled(dnsSrvEnabled)
+ .dcpEnabled(dcpEnabled)
+ .sslEnabled(sslEnabled)
+ .sslKeystoreFile(sslKeystoreFile)
+ .sslKeystorePassword(sslKeystorePassword)
+ .queryEnabled(queryEnabled)
+ .queryPort(queryPort)
+ .bootstrapHttpEnabled(bootstrapHttpEnabled)
+ .bootstrapCarrierEnabled(bootstrapCarrierEnabled)
+ .bootstrapHttpDirectPort(bootstrapHttpDirectPort)
+ .bootstrapHttpSslPort(bootstrapHttpSslPort)
+ .bootstrapCarrierDirectPort(bootstrapCarrierDirectPort)
+ .bootstrapCarrierSslPort(bootstrapCarrierSslPort)
+ .ioPoolSize(ioPoolSize)
+ .computationPoolSize(computationPoolSize)
+ .responseBufferSize(responseBufferSize)
+ .requestBufferSize(requestBufferSize)
+ .kvEndpoints(kvEndpoints)
+ .viewEndpoints(viewEndpoints)
+ .queryEndpoints(queryEndpoints)
+ .retryStrategy(retryStrategy)
+ .maxRequestLifetime(maxRequestLifetime)
+ .keepAliveInterval(keepAliveInterval)
+ .autoreleaseAfter(autoreleaseAfter)
+ .bufferPoolingEnabled(bufferPoolingEnabled)
+ .build();
+ }
+
+ /**
+ * Sets the {@link RetryStrategy} to use from an enum-like String value.
+ * Either "FailFast" or "BestEffort" are recognized.
+ *
+ * @param retryStrategy the string value enum from which to choose a strategy.
+ */
+ public void setRetryStrategy(String retryStrategy) {
+ if (RETRYSTRATEGY_FAILFAST.equals(retryStrategy)){
+ this.retryStrategy = FailFastRetryStrategy.INSTANCE;
+ } else if (RETRYSTRATEGY_BESTEFFORT.equals(retryStrategy)) {
+ this.retryStrategy = BestEffortRetryStrategy.INSTANCE;
+ }
+ }
+
+ //==== SETTERS for the factory bean ====
+
+ public void setManagementTimeout(long managementTimeout) {
+ this.managementTimeout = managementTimeout;
+ }
+
+ public void setQueryTimeout(long queryTimeout) {
+ this.queryTimeout = queryTimeout;
+ }
+
+ public void setViewTimeout(long viewTimeout) {
+ this.viewTimeout = viewTimeout;
+ }
+
+ public void setKvTimeout(long kvTimeout) {
+ this.kvTimeout = kvTimeout;
+ }
+
+ public void setConnectTimeout(long connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public void setDisconnectTimeout(long disconnectTimeout) {
+ this.disconnectTimeout = disconnectTimeout;
+ }
+
+ public void setDnsSrvEnabled(boolean dnsSrvEnabled) {
+ this.dnsSrvEnabled = dnsSrvEnabled;
+ }
+
+ public void setDcpEnabled(boolean dcpEnabled) {
+ this.dcpEnabled = dcpEnabled;
+ }
+
+ public void setSslEnabled(boolean sslEnabled) {
+ this.sslEnabled = sslEnabled;
+ }
+
+ public void setSslKeystoreFile(String sslKeystoreFile) {
+ this.sslKeystoreFile = sslKeystoreFile;
+ }
+
+ public void setSslKeystorePassword(String sslKeystorePassword) {
+ this.sslKeystorePassword = sslKeystorePassword;
+ }
+
+ public void setQueryEnabled(boolean queryEnabled) {
+ this.queryEnabled = queryEnabled;
+ }
+
+ public void setQueryPort(int queryPort) {
+ this.queryPort = queryPort;
+ }
+
+ public void setBootstrapHttpEnabled(boolean bootstrapHttpEnabled) {
+ this.bootstrapHttpEnabled = bootstrapHttpEnabled;
+ }
+
+ public void setBootstrapCarrierEnabled(boolean bootstrapCarrierEnabled) {
+ this.bootstrapCarrierEnabled = bootstrapCarrierEnabled;
+ }
+
+ public void setBootstrapHttpDirectPort(int bootstrapHttpDirectPort) {
+ this.bootstrapHttpDirectPort = bootstrapHttpDirectPort;
+ }
+
+ public void setBootstrapHttpSslPort(int bootstrapHttpSslPort) {
+ this.bootstrapHttpSslPort = bootstrapHttpSslPort;
+ }
+
+ public void setBootstrapCarrierDirectPort(int bootstrapCarrierDirectPort) {
+ this.bootstrapCarrierDirectPort = bootstrapCarrierDirectPort;
+ }
+
+ public void setBootstrapCarrierSslPort(int bootstrapCarrierSslPort) {
+ this.bootstrapCarrierSslPort = bootstrapCarrierSslPort;
+ }
+
+ public void setIoPoolSize(int ioPoolSize) {
+ this.ioPoolSize = ioPoolSize;
+ }
+
+ public void setComputationPoolSize(int computationPoolSize) {
+ this.computationPoolSize = computationPoolSize;
+ }
+
+ public void setResponseBufferSize(int responseBufferSize) {
+ this.responseBufferSize = responseBufferSize;
+ }
+
+ public void setRequestBufferSize(int requestBufferSize) {
+ this.requestBufferSize = requestBufferSize;
+ }
+
+ public void setKvEndpoints(int kvEndpoints) {
+ this.kvEndpoints = kvEndpoints;
+ }
+
+ public void setViewEndpoints(int viewEndpoints) {
+ this.viewEndpoints = viewEndpoints;
+ }
+
+ public void setQueryEndpoints(int queryEndpoints) {
+ this.queryEndpoints = queryEndpoints;
+ }
+
+ public void setMaxRequestLifetime(long maxRequestLifetime) {
+ this.maxRequestLifetime = maxRequestLifetime;
+ }
+
+ public void setKeepAliveInterval(long keepAliveInterval) {
+ this.keepAliveInterval = keepAliveInterval;
+ }
+
+ public void setAutoreleaseAfter(long autoreleaseAfter) {
+ this.autoreleaseAfter = autoreleaseAfter;
+ }
+
+ public void setBufferPoolingEnabled(boolean bufferPoolingEnabled) {
+ this.bufferPoolingEnabled = bufferPoolingEnabled;
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java
new file mode 100644
index 00000000..6733a942
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java
@@ -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 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();
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java
new file mode 100644
index 00000000..b4bf013f
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java
@@ -0,0 +1,141 @@
+/*
+ * 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 static org.springframework.data.config.ParsingUtils.setPropertyValue;
+
+import com.couchbase.client.core.retry.RetryStrategy;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+import org.w3c.dom.Element;
+
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+
+/**
+ * Allows creation of a {@link DefaultCouchbaseEnvironment} via spring XML configuration.
+ *
+ *
+ * @author Simon Baslé
+ */
+public class CouchbaseEnvironmentParser 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_ENV;
+ }
+
+ /**
+ * 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 CouchbaseEnvironmentFactoryBean.class;
+ }
+
+ /**
+ * Parse the bean definition and build up the bean.
+ *
+ * @param envElement the XML element which contains the attributes.
+ * @param envDefinitionBuilder the builder which builds the bean.
+ */
+ @Override
+ protected void doParse(final Element envElement, final BeanDefinitionBuilder envDefinitionBuilder) {
+ setPropertyValue(envDefinitionBuilder, envElement, "managementTimeout", "managementTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "queryTimeout", "queryTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "viewTimeout", "viewTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "kvTimeout", "kvTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "connectTimeout", "connectTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "disconnectTimeout", "disconnectTimeout");
+ setPropertyValue(envDefinitionBuilder, envElement, "dnsSrvEnabled", "dnsSrvEnabled");
+
+ setPropertyValue(envDefinitionBuilder, envElement, "dcpEnabled", "dcpEnabled");
+ setPropertyValue(envDefinitionBuilder, envElement, "sslEnabled", "sslEnabled");
+ setPropertyValue(envDefinitionBuilder, envElement, "sslKeystoreFile", "sslKeystoreFile");
+ setPropertyValue(envDefinitionBuilder, envElement, "sslKeystorePassword", "sslKeystorePassword");
+ setPropertyValue(envDefinitionBuilder, envElement, "queryEnabled", "queryEnabled");
+ setPropertyValue(envDefinitionBuilder, envElement, "queryPort", "queryPort");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpEnabled", "bootstrapHttpEnabled");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierEnabled", "bootstrapCarrierEnabled");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpDirectPort", "bootstrapHttpDirectPort");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpSslPort", "bootstrapHttpSslPort");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierDirectPort", "bootstrapCarrierDirectPort");
+ setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierSslPort", "bootstrapCarrierSslPort");
+ setPropertyValue(envDefinitionBuilder, envElement, "ioPoolSize", "ioPoolSize");
+ setPropertyValue(envDefinitionBuilder, envElement, "computationPoolSize", "computationPoolSize");
+ setPropertyValue(envDefinitionBuilder, envElement, "responseBufferSize", "responseBufferSize");
+ setPropertyValue(envDefinitionBuilder, envElement, "requestBufferSize", "requestBufferSize");
+ setPropertyValue(envDefinitionBuilder, envElement, "kvEndpoints", "kvEndpoints");
+ setPropertyValue(envDefinitionBuilder, envElement, "viewEndpoints", "viewEndpoints");
+ setPropertyValue(envDefinitionBuilder, envElement, "queryEndpoints", "queryEndpoints");
+ setPropertyValue(envDefinitionBuilder, envElement, "maxRequestLifetime", "maxRequestLifetime");
+ setPropertyValue(envDefinitionBuilder, envElement, "keepAliveInterval", "keepAliveInterval");
+ setPropertyValue(envDefinitionBuilder, envElement, "autoreleaseAfter", "autoreleaseAfter");
+ setPropertyValue(envDefinitionBuilder, envElement, "bufferPoolingEnabled", "bufferPoolingEnabled");
+
+ //retry strategy is particular, in the xsd this is an enum (FailFast, BestEffort)
+ setPropertyValue(envDefinitionBuilder, envElement, "retryStrategy", "retryStrategy");
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java
index fa916cdf..6541b132 100644
--- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -16,6 +16,9 @@
package org.springframework.data.couchbase.config;
+import com.couchbase.client.java.Bucket;
+import org.w3c.dom.Element;
+
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
@@ -25,15 +28,15 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.couchbase.monitor.ClientInfo;
import org.springframework.data.couchbase.monitor.ClusterInfo;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
/**
* Enables Parsing of the "" 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.
+ * {@link Bucket} object is solved through the "bucket-ref" attribute.
*
* @author Michael Nitschinger
+ * @author Simon Baslé
*/
public class CouchbaseJmxParser implements BeanDefinitionParser {
@@ -45,27 +48,28 @@ public class CouchbaseJmxParser implements BeanDefinitionParser {
* @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)) {
- name = BeanNames.COUCHBASE;
+ String bucketName = element.getAttribute("bucket-ref");
+ if (!StringUtils.hasText(bucketName)) {
+ bucketName = BeanNames.COUCHBASE_BUCKET;
}
- registerJmxComponents(name, element, parserContext);
+ registerJmxComponents(bucketName, element, parserContext);
return null;
}
/**
* 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.
+ * @parma refBucketName the reference name to the couchbase bucket.
*/
- protected void registerJmxComponents(final String refName, final Element element, final ParserContext parserContext) {
+ protected void registerJmxComponents(final String refBucketName,
+ final Element element, final ParserContext parserContext) {
Object eleSource = parserContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
- createBeanDefEntry(ClientInfo.class, compositeDef, refName, eleSource, parserContext);
- createBeanDefEntry(ClusterInfo.class, compositeDef, refName, eleSource, parserContext);
+ createBeanDefEntry(ClientInfo.class, compositeDef, refBucketName, eleSource, parserContext);
+ createBeanDefEntry(ClusterInfo.class, compositeDef, refBucketName, eleSource, parserContext);
parserContext.registerComponent(compositeDef);
}
@@ -75,12 +79,12 @@ public class CouchbaseJmxParser implements BeanDefinitionParser {
*
* @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 refName the reference name to the couchbase bucket.
* @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) {
+ final String refName, final Object eleSource, final ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
builder.getRawBeanDefinition().setSource(eleSource);
builder.addConstructorArgReference(refName);
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java
index 7a1b0f82..bebed47d 100644
--- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -16,13 +16,11 @@
package org.springframework.data.couchbase.config;
+import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
-import org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension;
-import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
-import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
- * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Couchbase configuration.
+ * {@link 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.
@@ -35,9 +33,10 @@ public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport {
* Register bean definition parsers in the namespace handler.
*/
public final void init() {
- RepositoryConfigurationExtension extension = new CouchbaseRepositoryConfigurationExtension();
- registerBeanDefinitionParser("repositories", new RepositoryBeanDefinitionParser(extension));
- registerBeanDefinitionParser("couchbase", new CouchbaseParser());
+ //TODO repositories (CouchbaseRepositoryConfigurationExtension and RepositoryBeanDefinitionParser)
+ registerBeanDefinitionParser("env", new CouchbaseEnvironmentParser());
+ registerBeanDefinitionParser("cluster", new CouchbaseClusterParser());
+ registerBeanDefinitionParser("bucket", new CouchbaseBucketParser());
registerBeanDefinitionParser("jmx", new CouchbaseJmxParser());
registerBeanDefinitionParser("template", new CouchbaseTemplateParser());
registerBeanDefinitionParser("translation-service", new CouchbaseTranslationServiceParser());
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java
deleted file mode 100644
index 52b01da5..00000000
--- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.config;
-
-import com.couchbase.client.CouchbaseClient;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
-import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.data.config.ParsingUtils;
-import org.springframework.data.couchbase.core.CouchbaseFactoryBean;
-import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
-
-import java.util.Properties;
-
-/**
- * Parser for "" 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 CouchbaseFactoryBean.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) {
- ParsingUtils.setPropertyValue(bean, element, "host", "host");
- ParsingUtils.setPropertyValue(bean, element, "bucket", "bucket");
- ParsingUtils.setPropertyValue(bean, element, "password", "password");
-
- setLogger();
- }
-
- private void setLogger() {
- Properties systemProperties = System.getProperties();
- systemProperties.put("net.spy.log.LoggerImpl", CouchbaseFactoryBean.DEFAULT_LOGGER_PROPERTY);
- System.setProperties(systemProperties);
- }
-
- /**
- * 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;
- }
-
-}
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java
index 66a2b0d8..59a63b5c 100644
--- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -16,13 +16,14 @@
package org.springframework.data.couchbase.config;
+import org.w3c.dom.Element;
+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
/**
* Parser for "" bean definitions.
@@ -39,7 +40,6 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser
* @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
@@ -52,7 +52,6 @@ public class CouchbaseTemplateParser 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
@@ -68,11 +67,11 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser
*/
@Override
protected void doParse(final Element element, final BeanDefinitionBuilder bean) {
- String clientRef = element.getAttribute("client-ref");
+ String bucketRef = element.getAttribute("bucket-ref");
String converterRef = element.getAttribute("converter-ref");
String translationServiceRef = element.getAttribute("translation-service-ref");
- bean.addConstructorArgReference(StringUtils.hasText(clientRef) ? clientRef : BeanNames.COUCHBASE);
+ bean.addConstructorArgReference(StringUtils.hasText(bucketRef) ? bucketRef : BeanNames.COUCHBASE_BUCKET);
if (StringUtils.hasText(converterRef)) {
bean.addConstructorArgReference(converterRef);
diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java
index eb4920cc..89f2e52a 100644
--- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java
+++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -17,13 +17,14 @@
package org.springframework.data.couchbase.config;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.w3c.dom.Element;
+
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
/**
* Enables Parsing of the "" configuration bean.
@@ -36,7 +37,6 @@ public class CouchbaseTranslationServiceParser extends AbstractSingleBeanDefinit
* Defines the bean class that will be constructed.
*
* @param element the XML element which contains the attributes.
- *
* @return the class type to instantiate.
*/
@Override
@@ -55,17 +55,18 @@ public class CouchbaseTranslationServiceParser extends AbstractSingleBeanDefinit
final String objectMapper = element.getAttribute("objectMapper");
if (StringUtils.hasText(objectMapper)) {
bean.addPropertyReference("objectMapper", objectMapper);
- } else {
+ }
+ else {
bean.addPropertyValue("objectMapper", new ObjectMapper());
}
}
+
/**
* 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 (e.g., "translationService")
*/
@Override
diff --git a/src/main/java/org/springframework/data/couchbase/config/package-info.java b/src/main/java/org/springframework/data/couchbase/config/package-info.java
new file mode 100644
index 00000000..4bfb6547
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/config/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains all classes needed for specific configuration of
+ * Spring Data Couchbase.
+ */
+package org.springframework.data.couchbase.config;
\ No newline at end of file
diff --git a/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java b/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java
index dfdcd8a3..8e7d90ef 100644
--- a/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java
+++ b/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -30,8 +30,8 @@ public interface BucketCallback {
* 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 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;
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java
index 16e24f16..d4aed17c 100644
--- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java
+++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013, 2014 the original author or authors.
+ * 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
+ * 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,
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java
index fd03b81e..369d4c4f 100644
--- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java
+++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -16,19 +16,41 @@
package org.springframework.data.couchbase.core;
-import com.couchbase.client.ObservedException;
-import com.couchbase.client.ObservedModifiedException;
-import com.couchbase.client.ObservedTimeoutException;
-import com.couchbase.client.protocol.views.InvalidViewException;
-import com.couchbase.client.vbucket.ConnectionException;
+import java.util.concurrent.TimeoutException;
+
+import com.couchbase.client.core.BackpressureException;
+import com.couchbase.client.core.BucketClosedException;
+import com.couchbase.client.core.DocumentConcurrentlyModifiedException;
+import com.couchbase.client.core.ReplicaNotConfiguredException;
+import com.couchbase.client.core.RequestCancelledException;
+import com.couchbase.client.core.ServiceNotAvailableException;
+import com.couchbase.client.core.config.ConfigurationException;
+import com.couchbase.client.core.endpoint.SSLException;
+import com.couchbase.client.core.endpoint.kv.AuthenticationException;
+import com.couchbase.client.core.env.EnvironmentException;
+import com.couchbase.client.core.state.NotConnectedException;
+import com.couchbase.client.java.error.BucketDoesNotExistException;
+import com.couchbase.client.java.error.CASMismatchException;
+import com.couchbase.client.java.error.DesignDocumentException;
+import com.couchbase.client.java.error.DocumentAlreadyExistsException;
+import com.couchbase.client.java.error.DurabilityException;
+import com.couchbase.client.java.error.InvalidPasswordException;
+import com.couchbase.client.java.error.RequestTooBigException;
+import com.couchbase.client.java.error.TemporaryFailureException;
+import com.couchbase.client.java.error.TemporaryLockFailureException;
+import com.couchbase.client.java.error.TranscodingException;
+import com.couchbase.client.java.error.ViewDoesNotExistException;
+
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.DataRetrievalFailureException;
+import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
+import org.springframework.dao.QueryTimeoutException;
+import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
-import java.util.concurrent.CancellationException;
-
/**
* Simple {@link PersistenceExceptionTranslator} for Couchbase.
@@ -38,6 +60,7 @@ import java.util.concurrent.CancellationException;
* should not be translated.
*
* @author Michael Nitschinger
+ * @author Simon Baslé
*/
public class CouchbaseExceptionTranslator implements PersistenceExceptionTranslator {
@@ -45,28 +68,59 @@ public class CouchbaseExceptionTranslator implements PersistenceExceptionTransla
* Translate Couchbase specific exceptions to spring exceptions if possible.
*
* @param ex the exception to translate.
- *
* @return the translated exception or null.
*/
@Override
public final DataAccessException translateExceptionIfPossible(final RuntimeException ex) {
- if (ex instanceof ConnectionException) {
+ if (ex instanceof InvalidPasswordException
+ || ex instanceof NotConnectedException
+ || ex instanceof ConfigurationException
+ || ex instanceof EnvironmentException
+ || ex instanceof InvalidPasswordException
+ || ex instanceof SSLException
+ || ex instanceof ServiceNotAvailableException
+ || ex instanceof BucketClosedException
+ || ex instanceof BucketDoesNotExistException
+ || ex instanceof AuthenticationException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
- if (ex instanceof ObservedException
- || ex instanceof ObservedTimeoutException
- || ex instanceof ObservedModifiedException) {
+ if (ex instanceof DocumentAlreadyExistsException) {
+ return new DuplicateKeyException(ex.getMessage(), ex);
+ }
+
+ if (ex instanceof CASMismatchException
+ || ex instanceof DocumentConcurrentlyModifiedException
+ || ex instanceof ReplicaNotConfiguredException
+ || ex instanceof DurabilityException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
- if (ex instanceof CancellationException) {
- throw new OperationCancellationException(ex.getMessage(), ex);
+ if (ex instanceof RequestCancelledException
+ || ex instanceof BackpressureException) {
+ return new OperationCancellationException(ex.getMessage(), ex);
}
- if (ex instanceof InvalidViewException) {
- throw new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
+ if (ex instanceof ViewDoesNotExistException
+ || ex instanceof RequestTooBigException
+ || ex instanceof DesignDocumentException) {
+ return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex);
+ }
+
+ if (ex instanceof TemporaryLockFailureException
+ || ex instanceof TemporaryFailureException) {
+ return new TransientDataAccessResourceException(ex.getMessage(), ex);
+ }
+
+ if ((ex instanceof RuntimeException && ex.getCause() instanceof TimeoutException)) {
+ return new QueryTimeoutException(ex.getMessage(), ex);
+ }
+
+ if (ex instanceof TranscodingException) {
+ //note: the more specific CouchbaseQueryExecutionException should be thrown by the template
+ //when dealing with TranscodingException in the query/n1ql methods.
+ return new DataRetrievalFailureException(ex.getMessage(), ex);
}
// Unable to translate exception, therefore just throw the original!
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java
deleted file mode 100644
index 8918efb9..00000000
--- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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;
-
-import com.couchbase.client.CouchbaseClient;
-import com.couchbase.client.CouchbaseConnectionFactory;
-import com.couchbase.client.CouchbaseConnectionFactoryBuilder;
-import net.spy.memcached.FailureMode;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.dao.DataAccessException;
-import org.springframework.dao.support.PersistenceExceptionTranslator;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 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, 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 = "";
-
- /**
- * The name of the default shutdown method to call when the context is destroyed.
- */
- public static final String DEFAULT_DESTROY_METHOD = "shutdown";
-
- /**
- * Use SLF4J as the default logger if not instructed otherwise.
- */
- public static final String DEFAULT_LOGGER_PROPERTY = "net.spy.memcached.compat.log.SLF4JLogger";
-
- /**
- * Holds the enclosed {@link CouchbaseClient}.
- */
- private CouchbaseClient couchbaseClient;
-
- /**
- * 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 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 bucket to be used.
- *
- * @param bucket the bucket to use.
- */
- public void setBucket(final String bucket) {
- this.bucket = bucket;
- }
-
- /**
- * Set the password.
- *
- * @param password the password to use.
- */
- public void setPassword(final String password) {
- this.password = password;
- }
-
- /**
- * Set the array of nodes from a delimited list of hosts.
- *
- * @param hosts a comma separated list of hosts.
- */
- public void setHost(final String hosts) {
- this.nodes = convertHosts(hosts);
- }
-
- /**
- * 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 convertHosts(final String hosts) {
- String[] split = hosts.split(",");
- List nodes = new ArrayList();
-
- try {
- for (int i = 0; i < split.length; i++) {
- nodes.add(new URI("http://" + split[i] + ":8091/pools"));
- }
- } catch (URISyntaxException ex) {
- throw new BeanCreationException("Could not convert host list." + ex);
- }
-
- return nodes;
- }
-
- /**
- * 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 the type of the elements.
- * @return the converted list.
- */
- private List filterNonNullElementsAsList(T[] elements) {
- if (elements == null) {
- return Collections.emptyList();
- }
-
- List candidateElements = new ArrayList();
- for (T element : elements) {
- if (element != null) {
- candidateElements.add(element);
- }
- }
-
- 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"));
- bucket = bucket != null ? bucket : DEFAULT_BUCKET;
- password = password != null ? password : DEFAULT_PASSWORD;
-
- CouchbaseConnectionFactory factory = builder.buildCouchbaseConnection(nodes, bucket, password);
- 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);
- }
-
-}
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java
index a50d8c98..0610c9e0 100644
--- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java
+++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013 the original author or authors.
+ * 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
+ * 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,
@@ -17,20 +17,26 @@
package org.springframework.data.couchbase.core;
-import com.couchbase.client.CouchbaseClient;
-import com.couchbase.client.protocol.views.Query;
-import com.couchbase.client.protocol.views.ViewResponse;
-import net.spy.memcached.PersistTo;
-import net.spy.memcached.ReplicateTo;
-import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
-
import java.util.Collection;
import java.util.List;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.PersistTo;
+import com.couchbase.client.java.ReplicateTo;
+import com.couchbase.client.java.query.Query;
+import com.couchbase.client.java.query.QueryParams;
+import com.couchbase.client.java.query.QueryResult;
+import com.couchbase.client.java.query.Statement;
+import com.couchbase.client.java.view.ViewQuery;
+import com.couchbase.client.java.view.ViewResult;
+
+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
+ * @author Simon Baslé
*/
public interface CouchbaseOperations {
@@ -169,50 +175,71 @@ public interface CouchbaseOperations {
*
* @param id the unique ID of the document.
* @param entityClass the entity to map to.
- *
* @return returns the found object or null otherwise.
*/
T findById(String id, Class entityClass);
+ //TODO add javadoc link to setIncludeDocs when GA
+
/**
* Query a View for a list of documents of type T.
*
- *
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.
+ *
There is no need to setIncludeDocs(boolean) explicitly, because it will be set to true all the
+ * time. It is valid to pass in a empty constructed {@link ViewQuery} object.
*
*
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.
*
- * @param design the name of the design document.
- * @param view the name of the viewName.
- * @param query the Query object to customize the viewName query.
+ * @param query the Query object (also specifying view design document and view name).
* @param entityClass the entity to map to.
- *
* @return the converted collection
*/
- List findByView(String design, String view, Query query, Class entityClass);
+ List findByView(ViewQuery query, Class entityClass);
/**
- * Query a View with direct access to the {@link ViewResponse}.
+ * Query a View with direct access to the {@link ViewResult}.
*
This method is available to ease the working with views by still wrapping exceptions into the Spring
* infrastructure.
*
It is especially needed if you want to run reduced viewName queries, because they can't be mapped onto entities
* directly.
*
- * @param design the name of the designDocument document.
- * @param view the name of the viewName.
- * @param query the Query object to customize the viewName query.
- *
- * @return ViewResponse containing the results of the query.
+ * @param query the Query object (also specifying view design document and view name).
+ * @return ViewResult containing the results of the query.
*/
- ViewResponse queryView(String design, String view, Query query);
+ ViewResult queryView(ViewQuery query);
+
+ /**
+ * Query the N1QL Service for JSON data of type T. This is done via a {@link Query} that can
+ * contain a {@link Statement}, additional query parameters ({@link QueryParams})
+ * and placeholder values if the statement contains placeholders.
+ *
Use {@link Query}'s factory methods to construct this.
+ *
+ * @param n1ql the N1QL query.
+ * @param entityClass the target class for the returned entities.
+ * @param the entity class
+ * @return the list of entities matching this query.
+ */
+ List findByN1QL(Query n1ql, Class entityClass);
+
+ /**
+ * Query the N1QL Service with direct access to the {@link QueryResult}.
+ *
+ * This is done via a {@link Query} that can
+ * contain a {@link Statement}, additional query parameters ({@link QueryParams})
+ * and placeholder values if the statement contains placeholders.
+ *
+ * Use {@link Query}'s factory methods to construct this.
+ *
+ * @param n1ql the N1QL query.
+ * @return {@link QueryResult} containing the results of the n1ql query.
+ */
+ QueryResult queryN1QL(Query n1ql);
/**
* Checks if the given document exists.
*
* @param id the unique ID of the document.
- *
* @return whether the document could be found or not.
*/
boolean exists(String id);
@@ -262,11 +289,17 @@ public interface CouchbaseOperations {
*
* @param action the action to execute in the callback.
* @param the return type.
- *
* @return the return type.
*/
T execute(BucketCallback action);
+ /**
+ * Returns the linked {@link Bucket} to this template.
+ *
+ * @return the client used for the template.
+ */
+ Bucket getCouchbaseBucket();
+
/**
* Returns the underlying {@link CouchbaseConverter}.
*
@@ -274,11 +307,4 @@ public interface CouchbaseOperations {
*/
CouchbaseConverter getConverter();
- /**
- * Returns the linked {@link CouchbaseClient} to this template.
- *
- * @return the client used for the template.
- */
- CouchbaseClient getCouchbaseClient();
-
}
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java
new file mode 100644
index 00000000..7cb25a90
--- /dev/null
+++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.core;
+
+import org.springframework.dao.DataRetrievalFailureException;
+
+/**
+ * An {@link DataRetrievalFailureException} that denotes an error during a query (N1QL).
+ */
+public class CouchbaseQueryExecutionException extends DataRetrievalFailureException {
+
+ public CouchbaseQueryExecutionException(String msg) {
+ super(msg);
+ }
+
+ public CouchbaseQueryExecutionException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java
index b91594d3..7f707c05 100644
--- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java
+++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013-2014 the original author or authors.
+ * 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
+ * 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,
@@ -16,22 +16,38 @@
package org.springframework.data.couchbase.core;
-import com.couchbase.client.CouchbaseClient;
-import com.couchbase.client.protocol.views.Query;
-import com.couchbase.client.protocol.views.View;
-import com.couchbase.client.protocol.views.ViewResponse;
-import com.couchbase.client.protocol.views.ViewRow;
-import net.spy.memcached.CASResponse;
-import net.spy.memcached.CASValue;
-import net.spy.memcached.PersistTo;
-import net.spy.memcached.ReplicateTo;
-import net.spy.memcached.internal.OperationFuture;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.PersistTo;
+import com.couchbase.client.java.ReplicateTo;
+import com.couchbase.client.java.document.Document;
+import com.couchbase.client.java.document.RawJsonDocument;
+import com.couchbase.client.java.document.json.JsonObject;
+import com.couchbase.client.java.error.CASMismatchException;
+import com.couchbase.client.java.error.TranscodingException;
+import com.couchbase.client.java.query.Query;
+import com.couchbase.client.java.query.QueryResult;
+import com.couchbase.client.java.query.QueryRow;
+import com.couchbase.client.java.view.ViewQuery;
+import com.couchbase.client.java.view.ViewResult;
+import com.couchbase.client.java.view.ViewRow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.QueryTimeoutException;
+import org.springframework.dao.support.PersistenceExceptionTranslator;
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;
@@ -50,34 +66,16 @@ import org.springframework.data.couchbase.core.mapping.event.CouchbaseMappingEve
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.BeanWrapper;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
/**
* @author Michael Nitschinger
* @author Oliver Gierke
+ * @author Simon Baslé
*/
public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(CouchbaseTemplate.class);
- private static final Collection ITERABLE_CLASSES;
private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE;
-
- private final CouchbaseClient client;
- protected final MappingContext extends CouchbasePersistentEntity>, CouchbasePersistentProperty> mappingContext;
- private final CouchbaseExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
- private final TranslationService translationService;
- private ApplicationEventPublisher eventPublisher;
-
- private CouchbaseConverter couchbaseConverter;
- private WriteResultChecking writeResultChecking = DEFAULT_WRITE_RESULT_CHECKING;
+ private static final Collection ITERABLE_CLASSES;
static {
final Set iterableClasses = new HashSet();
@@ -87,181 +85,66 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP
ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses);
}
- public void setWriteResultChecking(final WriteResultChecking resultChecking) {
- writeResultChecking = resultChecking == null ? DEFAULT_WRITE_RESULT_CHECKING : resultChecking;
- }
+ private final Bucket client;
+ private final CouchbaseConverter converter;
+ private final TranslationService translationService;
- public CouchbaseTemplate(final CouchbaseClient client) {
+
+ private ApplicationEventPublisher eventPublisher;
+ private WriteResultChecking writeResultChecking = DEFAULT_WRITE_RESULT_CHECKING;
+ private PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
+
+ protected final MappingContext extends CouchbasePersistentEntity>, CouchbasePersistentProperty> mappingContext;
+
+ public CouchbaseTemplate(final Bucket client) {
this(client, null, null);
}
- public CouchbaseTemplate(final CouchbaseClient client, final TranslationService translationService) {
+ public CouchbaseTemplate(final Bucket client, final TranslationService translationService) {
this(client, null, translationService);
}
- public CouchbaseTemplate(final CouchbaseClient client, final CouchbaseConverter couchbaseConverter, final TranslationService translationService) {
+ public CouchbaseTemplate(final Bucket client, final CouchbaseConverter converter,
+ final TranslationService translationService) {
this.client = client;
- this.couchbaseConverter = couchbaseConverter == null ? getDefaultConverter() : couchbaseConverter;
+ this.converter = converter == null ? getDefaultConverter() : converter;
this.translationService = translationService == null ? getDefaultTranslationService() : translationService;
- mappingContext = this.couchbaseConverter.getMappingContext();
+ this.mappingContext = this.converter.getMappingContext();
}
- @Override
- public void setApplicationEventPublisher(final ApplicationEventPublisher eventPublisher) {
- this.eventPublisher = eventPublisher;
+ private TranslationService getDefaultTranslationService() {
+ JacksonTranslationService t = new JacksonTranslationService();
+ t.afterPropertiesSet();
+ return t;
}
- private static CouchbaseConverter getDefaultConverter() {
- final MappingCouchbaseConverter converter = new MappingCouchbaseConverter(new CouchbaseMappingContext());
- converter.afterPropertiesSet();
- return converter;
+ private CouchbaseConverter getDefaultConverter() {
+ MappingCouchbaseConverter c = new MappingCouchbaseConverter(new CouchbaseMappingContext());
+ c.afterPropertiesSet();
+ return c;
}
- private static TranslationService getDefaultTranslationService() {
- final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService();
- jacksonTranslationService.afterPropertiesSet();
- return jacksonTranslationService;
- }
-
- private Object translateEncode(final CouchbaseStorable source) {
- return translationService.encode(source);
- }
-
-
- private CouchbaseStorable translateDecode(final String source, final CouchbaseStorable target) {
- return translationService.decode(source, target);
- }
-
- @Override
- public final void insert(final Object objectToInsert) {
- insert(objectToInsert, PersistTo.ZERO, ReplicateTo.ZERO);
- }
-
- @Override
- public final void insert(final Collection> batchToInsert) {
- for (final Object toInsert : batchToInsert) {
- insert(toInsert);
+ /**
+ * Encode a {@link CouchbaseDocument} into a storable representation (JSON) then prepare
+ * it for storage as a {@link Document}.
+ */
+ private Document encodeAndWrap(final CouchbaseDocument source, Long version) {
+ String encodedContent = translationService.encode(source);
+ if (version == null) {
+ return RawJsonDocument.create(source.getId(), source.getExpiration(), encodedContent);
+ }
+ else {
+ return RawJsonDocument.create(source.getId(), source.getExpiration(), encodedContent, version);
}
}
- @Override
- public void save(final Object objectToSave) {
- save(objectToSave, PersistTo.ZERO, ReplicateTo.ZERO);
- }
- @Override
- public void save(final Collection> batchToSave) {
- for (final Object toSave : batchToSave) {
- save(toSave);
- }
- }
-
- @Override
- public void update(final Object objectToUpdate) {
- update(objectToUpdate, PersistTo.ZERO, ReplicateTo.ZERO);
- }
-
- @Override
- public void update(final Collection> batchToUpdate) {
- for (final Object toUpdate : batchToUpdate) {
- update(toUpdate);
- }
- }
-
- @Override
- public final T findById(final String id, final Class entityClass) {
- CASValue result = execute(new BucketCallback() {
- @Override
- public CASValue doInBucket() {
- return client.gets(id);
- }
- });
-
- if (result == null) {
- return null;
- }
-
- final CouchbaseDocument converted = new CouchbaseDocument(id);
- Object readEntity = couchbaseConverter.read(entityClass, (CouchbaseDocument) translateDecode(
- (String) result.getValue(), converted));
-
- final BeanWrapper