DATACOUCH-135 - Migrate to Couchbase SDK 2.0 and add N1QL find method.

Adaptation were made to use SDK 2.0:
 - Reworked the configuration approach (more parts to be configured, like Environment, Cluster and Bucket)
 - Added a new xml schema for configuration of 2.0 version
 - Adapted the template
 - Added N1QL support in the template (findByN1QL)
 - Removed the cache package
 - Adapted the repository
 - Better separated Unit Tests from Integration Tests

All integration and unit tests pass, except one (SimpleCouchbaseRepositoryTests.shouldFindCustom).

Customisation of a ViewQuery will be addressed in another ticket.
This commit is contained in:
Simon Baslé
2015-07-02 18:50:08 +02:00
parent 28dcdee1db
commit b9f23f3fd5
126 changed files with 4203 additions and 3184 deletions

View File

@@ -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

267
pom.xml
View File

@@ -1,155 +1,164 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>1.4.0.BUILD-SNAPSHOT</version>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<name>Spring Data Couchbase</name>
<description>Spring Data integration for Couchbase</description>
<url>https://github.com/SpringSource/spring-data-couchbase</url>
<name>Spring Data Couchbase</name>
<description>Spring Data integration for Couchbase</description>
<url>https://github.com/SpringSource/spring-data-couchbase</url>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.7.0.BUILD-SNAPSHOT</version>
</parent>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.7.0.BUILD-SNAPSHOT</version>
</parent>
<properties>
<properties>
<dist.key>DATACOUCH</dist.key>
<dist.key>DATACOUCH</dist.key>
<couchbase>1.4.7</couchbase>
<jackson>2.3.2</jackson>
<springdata.commons>1.11.0.BUILD-SNAPSHOT</springdata.commons>
<validation>1.0.0.GA</validation>
</properties>
<couchbase>2.2.0-dp</couchbase>
<jackson>2.3.2</jackson>
<springdata.commons>1.11.0.BUILD-SNAPSHOT</springdata.commons>
<validation>1.0.0.GA</validation>
</properties>
<dependencies>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-data-commons</artifactId>
<version>${springdata.commons}</version>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>couchbase-client</artifactId>
<version>${couchbase}</version>
</dependency>
<dependency>
<groupId>com.couchbase.client</groupId>
<artifactId>java-client</artifactId>
<version>${couchbase}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime}</version>
<optional>true</optional>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation}</version>
<optional>true</optional>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- CDI -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.openwebbeans.test</groupId>
<artifactId>cditest-owb</artifactId>
<version>${webbeans}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencies>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
<repository>
<id>couchbase</id>
<name>couchbase repo</name>
<url>http://files.couchbase.com/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
</project>

View File

@@ -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<String> 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;
}
}

View File

@@ -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");
}
}

View File

@@ -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<String, Object> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, Object>>() {});
assertEquals("org.springframework.data.couchbase.core.Beer", resultConv.get("_class"));
assertEquals(false, resultConv.get("is_active"));
assertEquals("The Awesome Stout", resultConv.get("name"));
}
@Test
public void saveDocumentWithExpiry() throws Exception {
String id = "simple-doc-with-expiry";
DocumentWithExpiry doc = new DocumentWithExpiry(id);
template.save(doc);
assertNotNull(client.get(id));
Thread.sleep(3000);
assertNull(client.get(id));
}
@Test
public void insertDoesNotOverride() throws Exception {
String id = "double-insert-test";
removeIfExist(id);
SimplePerson doc = new SimplePerson(id, "Mr. A");
template.insert(doc);
RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class);
assertNotNull(resultDoc);
String result = resultDoc.content();
Map<String, String> resultConv = MAPPER.readValue(result, new TypeReference<Map<String, String>>() {});
assertEquals("Mr. A", resultConv.get("name"));
doc = new SimplePerson(id, "Mr. B");
template.insert(doc);
resultDoc = client.get(id, RawJsonDocument.class);
assertNotNull(resultDoc);
result = resultDoc.content();
resultConv = MAPPER.readValue(result, new TypeReference<Map<String, String>>() {});
assertEquals("Mr. A", resultConv.get("name"));
}
@Test
public void updateDoesNotInsert() {
String id = "update-does-not-insert";
SimplePerson doc = new SimplePerson(id, "Nice Guy");
template.update(doc);
assertNull(client.get(id));
}
@Test
public void removeDocument() {
String id = "beers:to-delete-stout";
Beer beer = new Beer(id);
template.save(beer);
Object result = client.get(id);
assertNotNull(result);
template.remove(beer);
result = client.get(id);
assertNull(result);
}
@Test
public void storeListsAndMaps() {
String id = "persons:lots-of-names";
List<String> names = new ArrayList<String>();
names.add("Michael");
names.add("Thomas");
names.add(null);
List<Integer> votes = new LinkedList<Integer>();
Map<String, Boolean> info1 = new HashMap<String, Boolean>();
info1.put("foo", true);
info1.put("bar", false);
info1.put("nullValue", null);
Map<String, Integer> info2 = new HashMap<String, Integer>();
ComplexPerson complex = new ComplexPerson(id, names, votes, info1, info2);
template.save(complex);
assertNotNull(client.get(id));
ComplexPerson response = template.findById(id, ComplexPerson.class);
assertEquals(names, response.getFirstnames());
assertEquals(votes, response.getVotes());
assertEquals(id, response.getId());
assertEquals(info1, response.getInfo1());
assertEquals(info2, response.getInfo2());
}
@Test
public void validFindById() {
String id = "beers:findme-stout";
String name = "The Findme Stout";
boolean active = true;
Beer beer = new Beer(id).setName(name).setActive(active);
template.save(beer);
Beer found = template.findById(id, Beer.class);
assertNotNull(found);
assertEquals(id, found.getId());
assertEquals(name, found.getName());
assertEquals(active, found.getActive());
}
@Test
public void shouldLoadAndMapViewDocs() {
ViewQuery query = ViewQuery.from("test_beers", "by_name");
query.stale(Stale.FALSE);
final List<Beer> beers = template.findByView(query, Beer.class);
assertTrue(beers.size() > 0);
for (Beer beer : beers) {
assertNotNull(beer.getId());
assertNotNull(beer.getName());
assertNotNull(beer.getActive());
}
}
@Test
public void shouldQueryRaw() {
Query query = Query.simple(select("name").from(i(client.name()))
.where(x("name").isNotMissing()));
QueryResult queryResult = template.queryN1QL(query);
assertNotNull(queryResult);
assertTrue(queryResult.errors().toString(), queryResult.finalSuccess());
assertFalse(queryResult.allRows().isEmpty());
}
@Test
public void shouldQueryWithMapping() {
FullFragment ff1 = new FullFragment("fullFragment1", 1, "fullFragment", "test1");
FullFragment ff2 = new FullFragment("fullFragment2", 2, "fullFragment", "test2");
template.save(Arrays.asList(ff1, ff2));
Query query = Query.simple(select(i("value")) //"value" is a n1ql keyword apparently
.from(i(client.name()))
.where(x("type").eq(s("fullFragment"))
.and(x("criteria").gt(1))));
List<Fragment> fragments = template.findByN1QL(query, Fragment.class);
assertNotNull(fragments);
assertFalse(fragments.isEmpty());
assertEquals(1, fragments.size());
assertEquals("test2", fragments.get(0).value);
}
@Test
public void shouldDeserialiseLongs() {
final long time = new Date().getTime();
SimpleWithLong simpleWithLong = new SimpleWithLong("simpleWithLong:simple", time);
template.save(simpleWithLong);
simpleWithLong = template.findById("simpleWithLong:simple", SimpleWithLong.class);
assertNotNull(simpleWithLong);
assertEquals(time, simpleWithLong.getValue());
}
@Test
public void shouldDeserialiseEnums() {
SimpleWithEnum simpleWithEnum = new SimpleWithEnum("simpleWithEnum:enum", SimpleWithEnum.Type.BIG);
template.save(simpleWithEnum);
simpleWithEnum = template.findById("simpleWithEnum:enum", SimpleWithEnum.class);
assertNotNull(simpleWithEnum);
assertEquals(simpleWithEnum.getType(), SimpleWithEnum.Type.BIG);
}
@Test
public void shouldDeserialiseClass() {
SimpleWithClass simpleWithClass = new SimpleWithClass("simpleWithClass:class", Integer.class);
simpleWithClass.setValue("The dish ran away with the spoon.");
template.save(simpleWithClass);
simpleWithClass = template.findById("simpleWithClass:class", SimpleWithClass.class);
assertNotNull(simpleWithClass);
assertThat(simpleWithClass.getValue(), equalTo("The dish ran away with the spoon."));
}
@Test
public void shouldHandleCASVersionOnInsert() throws Exception {
removeIfExist("versionedClass:1");
VersionedClass versionedClass = new VersionedClass("versionedClass:1", "foobar");
assertEquals(0, versionedClass.getVersion());
template.insert(versionedClass);
RawJsonDocument rawStored = client.get("versionedClass:1", RawJsonDocument.class);
assertEquals(rawStored.cas(), versionedClass.getVersion());
}
@Test
public void versionShouldNotUpdateOnSecondInsert() throws Exception {
removeIfExist("versionedClass:2");
VersionedClass versionedClass = new VersionedClass("versionedClass:2", "foobar");
template.insert(versionedClass);
long version1 = versionedClass.getVersion();
template.insert(versionedClass);
long version2 = versionedClass.getVersion();
assertTrue(version1 > 0);
assertTrue(version2 > 0);
assertEquals(version1, version2);
}
@Test
public void shouldSaveDocumentOnMatchingVersion() throws Exception {
removeIfExist("versionedClass:3");
VersionedClass versionedClass = new VersionedClass("versionedClass:3", "foobar");
template.insert(versionedClass);
long version1 = versionedClass.getVersion();
versionedClass.setField("foobar2");
template.save(versionedClass);
long version2 = versionedClass.getVersion();
assertTrue(version1 > 0);
assertTrue(version2 > 0);
assertNotEquals(version1, version2);
assertEquals("foobar2", template.findById("versionedClass:3", VersionedClass.class).getField());
}
@Test(expected = OptimisticLockingFailureException.class)
public void shouldNotSaveDocumentOnNotMatchingVersion() throws Exception {
removeIfExist("versionedClass:4");
VersionedClass versionedClass = new VersionedClass("versionedClass:4", "foobar");
template.insert(versionedClass);
RawJsonDocument toCompare = RawJsonDocument.create("versionedClass:4", "different");
assertNotNull(client.upsert(toCompare));
versionedClass.setField("foobar2");
//save (aka upsert) won't error in case of CAS mismatch anymore
template.update(versionedClass);
}
@Test
public void shouldUpdateDocumentOnMatchingVersion() throws Exception {
removeIfExist("versionedClass:5");
VersionedClass versionedClass = new VersionedClass("versionedClass:5", "foobar");
template.insert(versionedClass);
long version1 = versionedClass.getVersion();
versionedClass.setField("foobar2");
template.update(versionedClass);
long version2 = versionedClass.getVersion();
assertTrue(version1 > 0);
assertTrue(version2 > 0);
assertNotEquals(version1, version2);
assertEquals("foobar2", template.findById("versionedClass:5", VersionedClass.class).getField());
}
@Test(expected = OptimisticLockingFailureException.class)
public void shouldNotUpdateDocumentOnNotMatchingVersion() throws Exception {
removeIfExist("versionedClass:6");
VersionedClass versionedClass = new VersionedClass("versionedClass:6", "foobar");
template.insert(versionedClass);
RawJsonDocument toCompare = RawJsonDocument.create("versionedClass:6", "different");
assertNotNull(client.upsert(toCompare));
versionedClass.setField("foobar2");
template.update(versionedClass);
}
@Test
public void shouldLoadVersionPropertyOnFind() throws Exception {
removeIfExist("versionedClass:7");
VersionedClass versionedClass = new VersionedClass("versionedClass:7", "foobar");
template.insert(versionedClass);
assertTrue(versionedClass.getVersion() > 0);
VersionedClass foundClass = template.findById("versionedClass:7", VersionedClass.class);
assertEquals(versionedClass.getVersion(), foundClass.getVersion());
}
/**
* A sample document with just an id and property.
*/
@Document
static class SimplePerson {
@Id
private final String id;
@Field
private final String name;
public SimplePerson(String id, String name) {
this.id = id;
this.name = name;
}
}
/**
* A sample document that expires in 2 seconds.
*/
@Document(expiry = 2)
static class DocumentWithExpiry {
@Id
private final String id;
public DocumentWithExpiry(String id) {
this.id = id;
}
}
@Document
static class ComplexPerson {
@Id
private final String id;
@Field
private final List<String> firstnames;
@Field
private final List<Integer> votes;
@Field
private final Map<String, Boolean> info1;
@Field
private final Map<String, Integer> info2;
public ComplexPerson(String id, List<String> firstnames,
List<Integer> votes, Map<String, Boolean> info1,
Map<String, Integer> info2) {
this.id = id;
this.firstnames = firstnames;
this.votes = votes;
this.info1 = info1;
this.info2 = info2;
}
List<String> getFirstnames() {
return firstnames;
}
List<Integer> getVotes() {
return votes;
}
Map<String, Boolean> getInfo1() {
return info1;
}
Map<String, Integer> getInfo2() {
return info2;
}
String getId() {
return id;
}
}
@Document
static class SimpleWithLong {
@Id
private String id;
private long value;
SimpleWithLong(final String id, final long value) {
this.id = id;
this.value = value;
}
String getId() {
return id;
}
long getValue() {
return value;
}
void setValue(final long value) {
this.value = value;
}
}
static class SimpleWithEnum {
@Id
private String id;
private enum Type {
BIG
}
private Type type;
SimpleWithEnum(final String id, final Type type) {
this.id = id;
this.type = type;
}
String getId() {
return id;
}
void setId(final String id) {
this.id = id;
}
Type getType() {
return type;
}
void setType(final Type type) {
this.type = type;
}
}
static class SimpleWithClass {
@Id
private String id;
private Class<Integer> integerClass;
private String value;
SimpleWithClass(final String id, final Class<Integer> integerClass) {
this.id = id;
this.integerClass = integerClass;
}
String getId() {
return id;
}
void setId(final String id) {
this.id = id;
}
Class<Integer> getIntegerClass() {
return integerClass;
}
void setIntegerClass(final Class<Integer> integerClass) {
this.integerClass = integerClass;
}
String getValue() {
return value;
}
void setValue(final String value) {
this.value = value;
}
}
static class VersionedClass {
@Id
private String id;
@Version
private long version;
private String field;
VersionedClass(String id, String field) {
this.id = id;
this.field = field;
}
public String getId() {
return id;
}
public long getVersion() {
return version;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
@Document
static class FullFragment {
@Id
private String id;
private long criteria;
private String type;
private String value;
public FullFragment(String id, long criteria, String type, String value) {
this.id = id;
this.criteria = criteria;
this.type = type;
this.value = value;
}
public String getId() {
return id;
}
public long getCriteria() {
return criteria;
}
public String getType() {
return type;
}
public String getValue() {
return value;
}
public void setCriteria(long criteria) {
this.criteria = criteria;
}
public void setType(String type) {
this.type = type;
}
public void setValue(String value) {
this.value = value;
}
}
static class Fragment {
public String value;
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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 java.util.Collections;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.view.DefaultView;
import com.couchbase.client.java.view.DesignDocument;
import com.couchbase.client.java.view.View;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
/**
* @author Michael Nitschinger
*/
public class CouchbaseTemplateViewListener extends DependencyInjectionTestExecutionListener {
@Override
public void beforeTestClass(final TestContext testContext) throws Exception {
Bucket client = (Bucket) testContext.getApplicationContext().getBean("couchbaseBucket");
populateTestData(client);
createAndWaitForDesignDocs(client);
}
private void populateTestData(Bucket client) {
CouchbaseTemplate template = new CouchbaseTemplate(client);
for (int i = 0; i < 100; i++) {
Beer b = new Beer("testbeer-" + i).setName("MyBeer " + i).setActive(true);
template.save(b);
}
}
private void createAndWaitForDesignDocs(Bucket client) {
String mapFunction = "function (doc, meta) { if(doc._class == "
+ "\"org.springframework.data.couchbase.core.Beer\") { emit(doc.name, null); } }";
View view = DefaultView.create("by_name", mapFunction);
DesignDocument designDoc = DesignDocument.create("test_beers", Collections.singletonList(view));
client.bucketManager().upsertDesignDocument(designDoc);
}
}

View File

@@ -16,45 +16,44 @@
package org.springframework.data.couchbase.monitor;
import com.couchbase.client.CouchbaseClient;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.core.IsNot.not;
import com.couchbase.client.java.Bucket;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.TestApplicationConfig;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertFalse;
/**
* @author Michael Nitschinger
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestApplicationConfig.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class ClientInfoTests {
/**
* Contains a reference to the actual CouchbaseClient.
*/
@Autowired
private CouchbaseClient client;
/**
* Contains a reference to the actual CouchbaseClient.
*/
@Autowired
private Bucket client;
private ClientInfo ci;
private ClientInfo ci;
@Before
public void setup() throws Exception {
ci = new ClientInfo(client);
}
@Before
public void setup() throws Exception {
ci = new ClientInfo(client);
}
@Test
public void hostNames() {
String hostnames = ci.getHostNames();
assertThat(hostnames, not(isEmptyString()));
}
@Test
public void hostNames() {
String hostnames = ci.getHostNames();
assertThat(hostnames, not(isEmptyString()));
}
}

View File

@@ -16,46 +16,47 @@
package org.springframework.data.couchbase.monitor;
import com.couchbase.client.CouchbaseClient;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import com.couchbase.client.java.Bucket;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.TestApplicationConfig;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
/**
* @author Michael Nitschinger
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestApplicationConfig.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class ClusterInfoTests {
/**
* Contains a reference to the actual CouchbaseClient.
*/
@Autowired
private CouchbaseClient client;
/**
* Contains a reference to the actual CouchbaseClient.
*/
@Autowired
private Bucket client;
private ClusterInfo ci;
private ClusterInfo ci;
@Before
public void setup() throws Exception {
ci = new ClusterInfo(client);
}
@Before
public void setup() throws Exception {
ci = new ClusterInfo(client);
}
@Test
public void totalDiskAssigned() {
assertThat(ci.getTotalDiskAssigned(), greaterThan(0L));
}
@Test
public void totalDiskAssigned() {
assertThat(ci.getTotalDiskAssigned(), greaterThan(0L));
}
@Test
public void totalRAMUsed() {
assertThat(ci.getTotalRAMUsed(), greaterThan(0L));
}
@Test
public void totalRAMUsed() {
assertThat(ci.getTotalRAMUsed(), greaterThan(0L));
}
}

View File

@@ -16,11 +16,16 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.DesignDocument;
import com.couchbase.client.protocol.views.ViewDesign;
import net.spy.memcached.PersistTo;
import net.spy.memcached.ReplicateTo;
import java.util.Collections;
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.view.DefaultView;
import com.couchbase.client.java.view.DesignDocument;
import com.couchbase.client.java.view.View;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@@ -32,29 +37,29 @@ public class CouchbaseRepositoryViewListener extends DependencyInjectionTestExec
@Override
public void beforeTestClass(final TestContext testContext) throws Exception {
CouchbaseClient client = (CouchbaseClient) testContext.getApplicationContext().getBean("couchbaseClient");
Bucket client = (Bucket) testContext.getApplicationContext().getBean("couchbaseBucket");
populateTestData(client);
createAndWaitForDesignDocs(client);
}
private void populateTestData(final CouchbaseClient client) {
private void populateTestData(final Bucket client) {
CouchbaseTemplate template = new CouchbaseTemplate(client);
for (int i = 0; i < 100; i++) {
template.save(new User("testuser-" + i, "uname-" + i), PersistTo.MASTER, ReplicateTo.ZERO);
template.save(new User("testuser-" + i, "uname-" + i), PersistTo.MASTER, ReplicateTo.NONE);
}
}
private void createAndWaitForDesignDocs(final CouchbaseClient client) {
DesignDocument designDoc = new DesignDocument("user");
private void createAndWaitForDesignDocs(final Bucket client) {
String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository.User\") { emit(null, null); } }";
designDoc.setView(new ViewDesign("customFindAllView", mapFunction, "_count"));
View view = DefaultView.create("customFindAllView", mapFunction, "_count");
List<View> views = Collections.singletonList(view);
DesignDocument designDoc = DesignDocument.create("user", views);
client.bucketManager().upsertDesignDocument(designDoc);
client.createDesignDoc(designDoc);
designDoc = new DesignDocument("userCustom");
designDoc.setView(new ViewDesign("customCountView", mapFunction, "_count"));
client.createDesignDoc(designDoc);
view = DefaultView.create("customCountView", mapFunction, "_count");
views = Collections.singletonList(view);
designDoc = DesignDocument.create("userCustom", views);
client.bucketManager().upsertDesignDocument(designDoc);
}
}

View File

@@ -16,34 +16,35 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.Query;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.view.Stale;
import com.couchbase.client.java.view.ViewQuery;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.couchbase.TestApplicationConfig;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static com.couchbase.client.protocol.views.Stale.FALSE;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author David Harrigan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestApplicationConfig.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(CouchbaseRepositoryViewListener.class)
public class CouchbaseRepositoryViewTests {
@Autowired
private CouchbaseClient client;
private Bucket client;
@Autowired
private CouchbaseTemplate template;
@@ -57,7 +58,7 @@ public class CouchbaseRepositoryViewTests {
@Test
public void shouldFindAllWithCustomView() {
client.query(client.getView("user", "customFindAllView"), new Query().setStale(FALSE));
client.query(ViewQuery.from("user", "customFindAllView").stale(Stale.FALSE));
Iterable<User> allUsers = repository.findAll();
int i = 0;
for (final User allUser : allUsers) {
@@ -68,7 +69,7 @@ public class CouchbaseRepositoryViewTests {
@Test
public void shouldCountWithCustomView() {
client.query(client.getView("userCustom", "customCountView"), new Query().setStale(FALSE));
client.query(ViewQuery.from("userCustom", "customCountView").stale(Stale.FALSE));
final long value = repository.count();
assertThat(value, is(100L));
}

View File

@@ -16,11 +16,16 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.DesignDocument;
import com.couchbase.client.protocol.views.ViewDesign;
import net.spy.memcached.PersistTo;
import net.spy.memcached.ReplicateTo;
import java.util.Collections;
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.view.DefaultView;
import com.couchbase.client.java.view.DesignDocument;
import com.couchbase.client.java.view.View;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@@ -32,27 +37,28 @@ public class SimpleCouchbaseRepositoryListener extends DependencyInjectionTestEx
@Override
public void beforeTestClass(final TestContext testContext) throws Exception {
CouchbaseClient client = (CouchbaseClient) testContext.getApplicationContext().getBean("couchbaseClient");
Bucket client = (Bucket) testContext.getApplicationContext().getBean("couchbaseBucket");
populateTestData(client);
createAndWaitForDesignDocs(client);
}
private void populateTestData(CouchbaseClient client) {
private void populateTestData(Bucket client) {
CouchbaseTemplate template = new CouchbaseTemplate(client);
for (int i = 0; i < 100; i++) {
User u = new User("testuser-" + i, "uname-" + i);
template.save(u, PersistTo.MASTER, ReplicateTo.ZERO);
template.save(u, PersistTo.MASTER, ReplicateTo.NONE);
}
}
private void createAndWaitForDesignDocs(CouchbaseClient client) {
DesignDocument designDoc = new DesignDocument("user");
private void createAndWaitForDesignDocs(Bucket client) {
String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository." +
"User\") { emit(null, null); } }";
designDoc.setView(new ViewDesign("all", mapFunction, "_count"));
client.createDesignDoc(designDoc);
View view = DefaultView.create("all", mapFunction, "_count");
List<View> views = Collections.singletonList(view);
DesignDocument designDoc = DesignDocument.create("user", views);
client.bucketManager().upsertDesignDocument(designDoc);
}
}

View File

@@ -16,15 +16,17 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.Query;
import com.couchbase.client.protocol.views.Stale;
import static org.junit.Assert.*;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.view.Stale;
import com.couchbase.client.java.view.ViewQuery;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.couchbase.TestApplicationConfig;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
@@ -32,18 +34,16 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
/**
* @author Michael Nitschinger
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestApplicationConfig.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
public class SimpleCouchbaseRepositoryTests {
@Autowired
private CouchbaseClient client;
private Bucket client;
@Autowired
private CouchbaseTemplate template;
@@ -79,7 +79,7 @@ public class SimpleCouchbaseRepositoryTests {
*/
public void shouldFindAll() {
// do a non-stale query to populate data for testing.
client.query(client.getView("user", "all"), new Query().setStale(Stale.FALSE));
client.query(ViewQuery.from("user", "all").stale(Stale.FALSE));
Iterable<User> allUsers = repository.findAll();
int size = 0;
@@ -94,14 +94,14 @@ public class SimpleCouchbaseRepositoryTests {
@Test
public void shouldCount() {
// do a non-stale query to populate data for testing.
client.query(client.getView("user", "all"), new Query().setStale(Stale.FALSE));
client.query(ViewQuery.from("user", "all").stale(Stale.FALSE));
assertEquals(100, repository.count());
}
@Test
public void shouldFindCustom() {
Iterable<User> users = repository.customViewQuery(new Query().setLimit(2).setStale(Stale.FALSE));
Iterable<User> users = repository.customViewQuery(ViewQuery.from("", "").limit(2).stale(Stale.FALSE));
int size = 0;
for (User u : users) {
size++;

View File

@@ -16,7 +16,8 @@
package org.springframework.data.couchbase.repository;
import com.couchbase.client.protocol.views.Query;
import com.couchbase.client.java.view.ViewQuery;
import org.springframework.data.couchbase.core.view.View;
/**
@@ -25,6 +26,6 @@ import org.springframework.data.couchbase.core.view.View;
public interface UserRepository extends CouchbaseRepository<User, String> {
@View(designDocument = "user", viewName = "all")
Iterable<User> customViewQuery(Query query);
Iterable<User> customViewQuery(ViewQuery query);
}

View File

@@ -18,8 +18,7 @@ package org.springframework.data.couchbase.repository.cdi;
import javax.inject.Inject;
import com.couchbase.client.CouchbaseClient;
import org.springframework.data.couchbase.repository.UserRepository;
import com.couchbase.client.java.Bucket;
/**
* @author Mark Paluch
@@ -30,13 +29,13 @@ class CdiRepositoryClient {
private CdiPersonRepository cdiPersonRepository;
@Inject
private CouchbaseClient couchbaseClient;
private Bucket couchbaseClient;
public CdiPersonRepository getCdiPersonRepository() {
return cdiPersonRepository;
}
public CouchbaseClient getCouchbaseClient() {
public Bucket getCouchbaseClient() {
return couchbaseClient;
}
}

View File

@@ -18,6 +18,13 @@ package org.springframework.data.couchbase.repository.cdi;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.List;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.view.DefaultView;
import com.couchbase.client.java.view.DesignDocument;
import com.couchbase.client.java.view.View;
import org.apache.webbeans.cditest.CdiTestContainer;
import org.apache.webbeans.cditest.CdiTestContainerLoader;
import org.junit.AfterClass;
@@ -25,10 +32,6 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.couchbase.client.CouchbaseClient;
import com.couchbase.client.protocol.views.DesignDocument;
import com.couchbase.client.protocol.views.ViewDesign;
/**
* @author Mark Paluch
*/
@@ -36,7 +39,7 @@ public class CdiRepositoryTests {
private static CdiTestContainer cdiContainer;
private CdiPersonRepository repository;
private CouchbaseClient couchbaseClient;
private Bucket couchbaseClient;
@BeforeClass
public static void init() throws Exception {
@@ -61,12 +64,13 @@ public class CdiRepositoryTests {
}
private void createAndWaitForDesignDocs(CouchbaseClient client) {
DesignDocument designDoc = new DesignDocument("person");
private void createAndWaitForDesignDocs(Bucket client) {
String mapFunction = "function (doc, meta) { if(doc._class == \"" + Person.class.getName()
+ "\") { emit(null, null); } }";
designDoc.setView(new ViewDesign("all", mapFunction, "_count"));
client.createDesignDoc(designDoc);
View view = DefaultView.create("all", mapFunction, "_count");
List<View> views = Collections.singletonList(view);
DesignDocument designDoc = DesignDocument.create("person", views);
client.bucketManager().upsertDesignDocument(designDoc);
}
/**

View File

@@ -19,27 +19,30 @@ package org.springframework.data.couchbase.repository.cdi;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import org.springframework.data.couchbase.core.CouchbaseFactoryBean;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.CouchbaseClient;
import org.springframework.data.couchbase.config.CouchbaseBucketFactoryBean;
/**
* Producer for {@link CouchbaseClient}. Defaults from {@link CouchbaseFactoryBean} are sufficient for our test.
* Producer for {@link Bucket}. A default {@link CouchbaseCluster} with defaults
* from {@link CouchbaseBucketFactoryBean} are sufficient for our test.
*
* @author Mark Paluch
* @author Simon Baslé
*/
class CouchbaseClientProducer {
@Produces
public CouchbaseClient createCouchbaseClient() throws Exception {
CouchbaseFactoryBean couchbaseFactoryBean = new CouchbaseFactoryBean();
couchbaseFactoryBean.setBucket("default");
public Bucket createCouchbaseClient() throws Exception {
//FIXME produce a Cluster and close it properly?
CouchbaseBucketFactoryBean couchbaseFactoryBean = new CouchbaseBucketFactoryBean(
CouchbaseCluster.create(), "default");
couchbaseFactoryBean.afterPropertiesSet();
return couchbaseFactoryBean.getObject();
}
public void close(@Disposes CouchbaseClient couchbaseClient) {
couchbaseClient.shutdown();
public void close(@Disposes Bucket couchbaseClient) {
couchbaseClient.close();
}
}

View File

@@ -18,11 +18,11 @@ package org.springframework.data.couchbase.repository.cdi;
import javax.enterprise.inject.Produces;
import com.couchbase.client.java.Bucket;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import com.couchbase.client.CouchbaseClient;
/**
* Produces a {@link CouchbaseOperations} instance for test usage.
* @author Mark Paluch
@@ -30,7 +30,7 @@ import com.couchbase.client.CouchbaseClient;
class CouchbaseOperationsProducer {
@Produces
public CouchbaseOperations createCouchbaseOperations(CouchbaseClient couchbaseClient) throws Exception {
public CouchbaseOperations createCouchbaseOperations(Bucket couchbaseClient) throws Exception {
CouchbaseTemplate couchbaseTemplate = new CouchbaseTemplate(couchbaseClient);

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

View File

@@ -6,18 +6,12 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/couchbase http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd">
<couchbase:couchbase id="cb-first" bucket="default" password="" host="localhost" />
<couchbase:couchbase id="cb-second" bucket="default" password="" host="localhost" />
<couchbase:env/>
<couchbase:cluster/>
<couchbase:template id="cb-template-first" client-ref="cb-first" />
<couchbase:template id="cb-template-second" client-ref="cb-second" />
<couchbase:repositories base-package="com.example" couchbase-template-ref="cb-template-first">
<data-repository:include-filter type="regex" expression=".*ARepository" />
</couchbase:repositories>
<couchbase:repositories base-package="com.example" couchbase-template-ref="cb-template-second">
<data-repository:include-filter type="regex" expression=".*BRepository" />
</couchbase:repositories>
<couchbase:bucket id="cb-first"/>
<couchbase:bucket id="cb-second"/>
<couchbase:template id="cb-template-first" bucket-ref="cb-first" />
<couchbase:template id="cb-template-second" bucket-ref="cb-second" />
</beans>

View File

@@ -5,7 +5,9 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/couchbase http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<couchbase:couchbase/>
<couchbase:env/>
<couchbase:cluster/>
<couchbase:bucket/>
<couchbase:template/>

View File

@@ -5,7 +5,9 @@
xsi:schemaLocation="http://www.springframework.org/schema/data/couchbase http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<couchbase:couchbase/>
<couchbase:env/>
<couchbase:cluster/>
<couchbase:bucket/>
<couchbase:template translation-service-ref="myCustomTranslationService"/>

View File

@@ -1,167 +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.cache;
import com.couchbase.client.CouchbaseClient;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
/**
* The {@link CouchbaseCache} class implements the Spring Cache interface on top of Couchbase Server and the Couchbase
* Java SDK.
*
* @see <a href="http://static.springsource.org/spring/docs/current/spring-framework-reference/html/cache.html">
* Official Spring Cache Reference</a>
* @author Michael Nitschinger
* @author Konrad Król
*/
public class CouchbaseCache implements Cache {
/**
* The actual CouchbaseClient instance.
*/
private final CouchbaseClient client;
/**
* The name of the cache.
*/
private final String name;
/**
* TTL value for objects in this cache
*/
private final int ttl;
/**
* Construct the cache and pass in the CouchbaseClient instance.
*
* @param name the name of the cache reference.
* @param client the CouchbaseClient instance.
*/
public CouchbaseCache(final String name, final CouchbaseClient client) {
this.name = name;
this.client = client;
this.ttl = 0;
}
/**
* Construct the cache and pass in the CouchbaseClient instance.
*
* @param name the name of the cache reference.
* @param client the CouchbaseClient instance.
* @param ttl TTL value for objects in this cache
*/
public CouchbaseCache(final String name, final CouchbaseClient client, int ttl) {
this.name = name;
this.client = client;
this.ttl = ttl;
}
/**
* Returns the name of the cache.
*
* @return the name of the cache.
*/
public final String getName() {
return name;
}
/**
* Returns the actual CouchbaseClient instance.
*
* @return the actual CouchbaseClient instance.
*/
public final CouchbaseClient getNativeCache() {
return client;
}
/**
* Returns the TTL value for this cache.
*
* @return TTL value
*/
public final int getTtl() {
return ttl;
}
/**
* Get an element from the cache.
*
* @param key the key to lookup against.
* @return the fetched value from Couchbase.
*/
public final ValueWrapper get(final Object key) {
String documentId = key.toString();
Object result = client.get(documentId);
return (result != null ? new SimpleValueWrapper(result) : null);
}
@SuppressWarnings("unchecked")
public final <T> T get(final Object key, final Class<T> clazz) {
String documentId = key.toString();
return (T) client.get(documentId);
}
/**
* Store a object in Couchbase.
*
* @param key the Key of the storable object.
* @param value the Object to store.
*/
public final void put(final Object key, final Object value) {
if (value != null) {
String documentId = key.toString();
client.set(documentId, ttl, value);
} else {
evict(key);
}
}
/**
* Remove an object from Couchbase.
*
* @param key the Key of the object to delete.
*/
public final void evict(final Object key) {
String documentId = key.toString();
client.delete(documentId);
}
/**
* Clear the complete cache.
*
* Note that this action is very destructive, so only use it with care.
* Also note that "flush" may not be enabled on the bucket.
*/
public final void clear() {
client.flush();
}
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object, java.lang.Object)
*/
public ValueWrapper putIfAbsent(Object key, Object value) {
if(get(key) == null) {
put(key, value);
return null;
}
return new SimpleValueWrapper(value);
}
}

View File

@@ -1,105 +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.cache;
import com.couchbase.client.CouchbaseClient;
import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
/**
* The {@link CouchbaseCacheManager} orchestrates {@link CouchbaseCache} instances.
*
* Since more than one current {@link CouchbaseClient} connection can be used for caching, the
* {@link CouchbaseCacheManager} orchestrates and handles them for the Spring Cache abstraction layer.
*
* @author Michael Nitschinger
* @author Konrad Król
*/
public class CouchbaseCacheManager extends AbstractCacheManager {
/**
* Holds the reference to all stored CouchbaseClient cache connections.
*/
private final HashMap<String, CouchbaseClient> clients;
/**
* Holds the TTL configuration for each cache.
*/
private final HashMap<String, Integer> ttlConfiguration;
/**
* Construct a new CouchbaseCacheManager.
*
* @param clients one ore more CouchbaseClients to reference.
*/
public CouchbaseCacheManager(final HashMap<String, CouchbaseClient> clients) {
this.clients = clients;
this.ttlConfiguration = new HashMap<String, Integer>();
}
/**
* Construct a new CouchbaseCacheManager.
*
* @param clients one ore more CouchbaseClients to reference.
* @param ttlConfiguration one or more TTL values (in seconds)
*/
public CouchbaseCacheManager(final HashMap<String, CouchbaseClient> clients, final HashMap<String, Integer> ttlConfiguration) {
this.clients = clients;
this.ttlConfiguration = ttlConfiguration;
}
/**
* Returns a Map of all CouchbaseClients with name.
*
* @return the actual CouchbaseClient instances.
*/
public final HashMap<String, CouchbaseClient> getClients() {
return clients;
}
/**
* Populates all caches.
*
* @return a collection of loaded caches.
*/
@Override
protected final Collection<? extends Cache> loadCaches() {
Collection<Cache> caches = new LinkedHashSet<Cache>();
for (Map.Entry<String, CouchbaseClient> cache : clients.entrySet()) {
caches.add(new CouchbaseCache(cache.getKey(), cache.getValue(), getTtl(cache.getKey())));
}
return caches;
}
/**
* Returns TTL value for single cache
* @param name cache name
* @return either the cache TTL value or 0 as a default value
*/
private int getTtl ( String name ) {
Integer expirationTime = ttlConfiguration.get(name);
return (expirationTime != null ? expirationTime : 0);
}
}

View File

@@ -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,14 +16,23 @@
package org.springframework.data.couchbase.config;
import com.couchbase.client.CouchbaseClient;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.couchbase.core.CouchbaseFactoryBean;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.convert.CustomConversions;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
@@ -37,29 +46,21 @@ import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
/**
* Base class for Spring Data Couchbase configuration using JavaConfig.
*
* @author Michael Nitschinger
* @author Simon Baslé
*/
@Configuration
public abstract class AbstractCouchbaseConfiguration {
/**
* The list of hostnames (or IP addresses to bootstrap from).
* The list of hostnames (or IP addresses) to bootstrap from.
*
* @return the list of bootstrap hosts.
*/
protected abstract List<String> bootstrapHosts();
protected abstract List<String> getBootstrapHosts();
/**
* The name of the bucket to connect to.
@@ -76,39 +77,54 @@ public abstract class AbstractCouchbaseConfiguration {
protected abstract String getBucketPassword();
/**
* Return the {@link CouchbaseClient} instance to connect to.
* Is the {@link #getEnvironment()} to be destroyed by Spring?
*
* @return true if Spring should destroy the environment with the context, false otherwise.
*/
protected boolean isEnvironmentManagedBySpring() {
return true;
}
/**
* Override this method if you want a customized {@link CouchbaseEnvironment}.
* This environment will be managed by Spring, which will call its shutdown()
* method upon bean destruction, unless you override {@link #isEnvironmentManagedBySpring()}
* as well to return false.
*
* @return a customized environment, defaults to a {@link DefaultCouchbaseEnvironment}.
*/
protected CouchbaseEnvironment getEnvironment() {
return DefaultCouchbaseEnvironment.create();
}
@Bean(destroyMethod = "shutdown", name = BeanNames.COUCHBASE_ENV)
public CouchbaseEnvironment couchbaseEnvironment() {
CouchbaseEnvironment env = getEnvironment();
if (isEnvironmentManagedBySpring()) {
return env;
}
return new CouchbaseEnvironmentNoShutdownProxy(env);
}
/**
* Returns the {@link Cluster} instance to connect to.
*
* @throws Exception on Bean construction failure.
*/
@Bean(destroyMethod = "shutdown")
public CouchbaseClient couchbaseClient() throws Exception {
setLoggerProperty(couchbaseLogger());
return new CouchbaseClient(
bootstrapUris(bootstrapHosts()),
getBucketName(),
getBucketPassword()
);
@Bean(destroyMethod = "disconnect", name = BeanNames.COUCHBASE_CLUSTER)
public Cluster couchbaseCluster() throws Exception {
return CouchbaseCluster.create(couchbaseEnvironment(), getBootstrapHosts());
}
/**
* Specifies the logger to use (defaults to SLF4J).
* Return the {@link Bucket} instance to connect to.
*
* @return the logger property string.
* @throws Exception on Bean construction failure.
*/
protected String couchbaseLogger() {
return CouchbaseFactoryBean.DEFAULT_LOGGER_PROPERTY;
}
/**
* Prepare the logging property before initializing couchbase.
*
* @param logger the logger path to use.
*/
protected static void setLoggerProperty(final String logger) {
Properties systemProperties = System.getProperties();
systemProperties.setProperty("net.spy.log.LoggerImpl", logger);
System.setProperties(systemProperties);
@Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET)
public Bucket couchbaseClient() throws Exception {
//@Bean method can use another @Bean method in the same @Configuration by directly invoking it
return couchbaseCluster().openBucket(getBucketName(), getBucketPassword());
}
/**
@@ -116,7 +132,7 @@ public abstract class AbstractCouchbaseConfiguration {
*
* @throws Exception on Bean construction failure.
*/
@Bean
@Bean(name = BeanNames.COUCHBASE_TEMPLATE)
public CouchbaseTemplate couchbaseTemplate() throws Exception {
return new CouchbaseTemplate(couchbaseClient(), mappingCouchbaseConverter(), translationService());
}
@@ -159,8 +175,6 @@ public abstract class AbstractCouchbaseConfiguration {
return mappingContext;
}
/**
* Register custom Converters in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the {@link #mappingCouchbaseConverter()} and
@@ -202,7 +216,7 @@ public abstract class AbstractCouchbaseConfiguration {
* will be considered {@code com.acme} unless the method is overridden to implement alternate behavior.</p>
*
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
* entities.
* 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<URI> bootstrapUris(List<String> hosts) throws URISyntaxException {
List<URI> uris = new ArrayList<URI>();
for (String host : hosts) {
uris.add(new URI("http://" + host + ":8091/pools"));
}
return uris;
}
}

View File

@@ -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 "<couchbase:couchbase />" bean.
* Refers to the "&lt;couchbase:env /&gt;" bean.
*/
static final String COUCHBASE = "couchbase";
static final String COUCHBASE_ENV = "couchbaseEnv";
/**
* Refers to the "&lt;couchbase:cluster /&gt;" bean.
*/
static final String COUCHBASE_CLUSTER = "couchbaseCluster";
/**
* Refers to the "<couchbase:template />" bean.
* Refers to the "&lt;couchbase:bucket /&gt;" bean.
*/
static final String COUCHBASE_BUCKET = "couchbaseBucket";
/**
* Refers to the "&lt;couchbase:template /&gt;" bean.
*/
static final String COUCHBASE_TEMPLATE = "couchbaseTemplate";
/**
* Refers to the "<couchbase:translation-service />" bean
* Refers to the "&lt;couchbase:translation-service /&gt;" bean
*/
static final String TRANSLATION_SERVICE = "translationService";
static final String TRANSLATION_SERVICE = "couchbaseTranslationService";
}

View File

@@ -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<Bucket> 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);
}
}

View File

@@ -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 <code>{@value BeanNames#COUCHBASE_CLUSTER}</code> is used.
*
* See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}.
*
* @author Simon Baslé
*/
public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser {
/**
* The <code>cluster-ref</code> attribute in a bucket definition defines the cluster to build from.
*/
public static final String CLUSTER_REF_ATTR = "cluster-ref";
/**
* The <code>bucketName</code> attribute in a bucket definition defines the name of the bucket to open.
*/
public static final String BUCKETNAME_ATTR = "bucketName";
/**
* The <code>bucketPassword</code> 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);
}
}
}

View File

@@ -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 &lt;{@value #CLUSTER_ENVIRONMENT_TAG}&gt; 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 &lt;{@value #CLUSTER_NODE_TAG}&gt; tags.
*
* @author Simon Baslé
*/
public class CouchbaseClusterParser extends AbstractSingleBeanDefinitionParser {
/**
* The &lt;node&gt; elements in a cluster definition define the bootstrap hosts to use
*/
public static final String CLUSTER_NODE_TAG = "node";
/**
* The unique &lt;env&gt; 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 &lt;env-ref&gt; 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<Element> nodes = DomUtils.getChildElementsByTagName(element, CLUSTER_NODE_TAG);
if (nodes != null && nodes.size() > 0) {
List<String> bootstrapUrls = new ArrayList<String>(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);
}
}

View File

@@ -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<CouchbaseEnvironment> {
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;
}
}

View File

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

View File

@@ -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.
* <p>
* The following properties are supported:<br/><ul>
* <li>{@link DefaultCouchbaseEnvironment.Builder#managementTimeout(long) managementTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#queryTimeout(long) queryTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#viewTimeout(long) viewTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#kvTimeout(long) kvTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#connectTimeout(long) connectTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#disconnectTimeout(long) disconnectTimeout}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#dnsSrvEnabled(boolean) dnsSrvEnabled}</li>
*
* <li>{@link DefaultCouchbaseEnvironment.Builder#dcpEnabled(boolean) dcpEnabled}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#sslEnabled(boolean) sslEnabled}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#sslKeystoreFile(String) sslKeystoreFile}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#sslKeystorePassword(String) sslKeystorePassword}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#queryEnabled(boolean) queryEnabled}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#queryPort(int) queryPort}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpEnabled(boolean) bootstrapHttpEnabled}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierEnabled(boolean) bootstrapCarrierEnabled}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpDirectPort(int) bootstrapHttpDirectPort}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpSslPort(int) bootstrapHttpSslPort}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierDirectPort(int) bootstrapCarrierDirectPort}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierSslPort(int) bootstrapCarrierSslPort}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#ioPoolSize(int) ioPoolSize}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#computationPoolSize(int) computationPoolSize}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#responseBufferSize(int) responseBufferSize}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#requestBufferSize(int) requestBufferSize}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#kvEndpoints(int) kvEndpoints}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#viewEndpoints(int) viewEndpoints}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#queryEndpoints(int) queryEndpoints}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#retryStrategy(RetryStrategy) retryStrategy}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#maxRequestLifetime(long) maxRequestLifetime}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#keepAliveInterval(long) keepAliveInterval}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#autoreleaseAfter(long) autoreleaseAfter}</li>
* <li>{@link DefaultCouchbaseEnvironment.Builder#bufferPoolingEnabled(boolean) bufferPoolingEnabled}</li>
* </ul>
*
* @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");
}
}

View File

@@ -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 "<couchbase:jmx />" configuration bean.
*
* <p/>
* 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);

View File

@@ -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.
* <p/>
* 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());

View File

@@ -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 "<couchbase:couchbase />" bean definitions.
* <p/>
* 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;
}
}

View File

@@ -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 "<couchbase:template />" 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);

View File

@@ -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 "<couchbase:translation-service />" 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

View File

@@ -0,0 +1,5 @@
/**
* This package contains all classes needed for specific configuration of
* Spring Data Couchbase.
*/
package org.springframework.data.couchbase.config;

View File

@@ -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<T> {
* The enclosed body will be executed on the connected bucket.
*
* @return the result of the enclosed execution.
* @throws TimeoutException if the enclosed operation timed out.
* @throws ExecutionException if the result could not be retrieved because of a thrown exception before.
* @throws TimeoutException if the enclosed operation timed out.
* @throws ExecutionException if the result could not be retrieved because of a thrown exception before.
* @throws InterruptedException if the enclosed operation was interrupted.
*/
T doInBucket() throws TimeoutException, ExecutionException, InterruptedException;

View File

@@ -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,

View File

@@ -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!

View File

@@ -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<CouchbaseClient>, InitializingBean,
DisposableBean, PersistenceExceptionTranslator {
/**
* Defines the default hostname to be used if no other list is supplied.
*/
public static final String DEFAULT_NODE = "127.0.0.1";
/**
* Defines the default bucket name to be used if no other bucket name is supplied.
*/
public static final String DEFAULT_BUCKET = "default";
/**
* Defines the password of the default bucket.
*/
public static final String DEFAULT_PASSWORD = "";
/**
* 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<URI> nodes;
/**
* The builder which allows to customize client settings.
*/
private final CouchbaseConnectionFactoryBuilder builder = new CouchbaseConnectionFactoryBuilder();
/**
* Set the observe poll interval in miliseconds.
*
* @param interval the observe poll interval.
*/
public void setObservePollInterval(final int interval) {
builder.setObsPollInterval(interval);
}
/**
* Set the maximum number of polls.
*
* @param max the maximum number of polls.
*/
public void setObservePollMax(final int max) {
builder.setObsPollMax(max);
}
/**
* Set the reconnect threshold time in seconds.
*
* @param time the reconnect threshold time.
*/
public void setReconnectThresholdTime(final int time) {
builder.setReconnectThresholdTime(time, TimeUnit.SECONDS);
}
/**
* Set the view timeout in miliseconds.
*
* @param timeout the view timeout.
*/
public void setViewTimeout(final int timeout) {
builder.setViewTimeout(timeout);
}
/**
* Set the failure mode if memcached buckets are used.
*
* See the proper values of {@link FailureMode} to use.
*
* @param mode the failure mode.
*/
public void setFailureMode(final String mode) {
builder.setFailureMode(FailureMode.valueOf(mode));
}
/**
* Set the operation timeout in miliseconds.
*
* @param timeout the operation timeout.
*/
public void setOpTimeout(final int timeout) {
builder.setOpTimeout(timeout);
}
/**
* Set the operation queue maximum block time in miliseconds.
*
* @param time the operation queue maximum block time.
*/
public void setOpQueueMaxBlockTime(final int time) {
builder.setOpQueueMaxBlockTime(time);
}
/**
* Shutdown the client when the bean is destroyed.
*
* @throws Exception if shutdown failed.
*/
@Override
public void destroy() throws Exception {
couchbaseClient.shutdown();
}
/**
* Return the underlying {@link CouchbaseClient}.
*
* @return the client object.
* @throws Exception if returning the client failed.
*/
@Override
public CouchbaseClient getObject() throws Exception {
return couchbaseClient;
}
/**
* Returns the object type of the client.
*
* @return the {@link CouchbaseClient} class.
*/
@Override
public Class<?> getObjectType() {
return CouchbaseClient.class;
}
/**
* The client should be returned as a singleton.
*
* @return returns true.
*/
@Override
public boolean isSingleton() {
return true;
}
/**
* Set the 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<URI> convertHosts(final String hosts) {
String[] split = hosts.split(",");
List<URI> nodes = new ArrayList<URI>();
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 <T> the type of the elements.
* @return the converted list.
*/
private <T> List<T> filterNonNullElementsAsList(T[] elements) {
if (elements == null) {
return Collections.emptyList();
}
List<T> candidateElements = new ArrayList<T>();
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);
}
}

View File

@@ -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> T findById(String id, Class<T> entityClass);
//TODO add javadoc link to setIncludeDocs when GA
/**
* Query a View for a list of documents of type T.
* <p/>
* <p>There is no need to {@link Query#setIncludeDocs(boolean)} explicitely, because it will be set to true all the
* time. It is valid to pass in a empty constructed {@link Query} object.</p>
* <p>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.</p>
* <p/>
* <p>This method does not work with reduced views, because they by design do not contain references to original
* objects. Use the provided {@link #queryView} method for more flexibility and direct access.</p>
*
* @param design the name of the design document.
* @param view the name of the 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
*/
<T> List<T> findByView(String design, String view, Query query, Class<T> entityClass);
<T> List<T> findByView(ViewQuery query, Class<T> entityClass);
/**
* Query a View with direct access to the {@link ViewResponse}.
* Query a View with direct access to the {@link ViewResult}.
* <p>This method is available to ease the working with views by still wrapping exceptions into the Spring
* infrastructure.</p>
* <p>It is especially needed if you want to run reduced viewName queries, because they can't be mapped onto entities
* directly.</p>
*
* @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.
* <p>Use {@link Query}'s factory methods to construct this.</p>
*
* @param n1ql the N1QL query.
* @param entityClass the target class for the returned entities.
* @param <T> the entity class
* @return the list of entities matching this query.
*/
<T> List<T> findByN1QL(Query n1ql, Class<T> entityClass);
/**
* Query the N1QL Service with direct access to the {@link QueryResult}.
* <p>
* 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.</p>
* <p>
* Use {@link Query}'s factory methods to construct this.</p>
*
* @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 <T> the return type.
*
* @return the return type.
*/
<T> T execute(BucketCallback<T> 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();
}

View File

@@ -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);
}
}

View File

@@ -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<String> 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<String> ITERABLE_CLASSES;
static {
final Set<String> iterableClasses = new HashSet<String>();
@@ -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<String> 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> T findById(final String id, final Class<T> entityClass) {
CASValue result = execute(new BucketCallback<CASValue>() {
@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<Object> beanWrapper = BeanWrapper.create(readEntity, couchbaseConverter.getConversionService());
CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(readEntity.getClass());
if (persistentEntity.hasVersionProperty()) {
beanWrapper.setProperty(persistentEntity.getVersionProperty(), result.getCas());
}
return (T) readEntity;
}
@Override
public <T> List<T> findByView(final String designName, final String viewName, final Query query, final Class<T> entityClass) {
if (query.willIncludeDocs()) {
query.setIncludeDocs(false);
}
if (query.willReduce()) {
query.setReduce(false);
}
final ViewResponse response = queryView(designName, viewName, query);
final List<T> result = new ArrayList<T>(response.size());
for (final ViewRow row : response) {
result.add(findById(row.getId(), entityClass));
}
return result;
}
@Override
public ViewResponse queryView(final String designName, final String viewName, final Query query) {
return execute(new BucketCallback<ViewResponse>() {
@Override
public ViewResponse doInBucket() {
final View view = client.getView(designName, viewName);
return client.query(view, query);
}
});
}
@Override
public void remove(final Object objectToRemove) {
remove(objectToRemove, PersistTo.ZERO, ReplicateTo.ZERO);
}
@Override
public void remove(final Collection<?> batchToRemove) {
for (final Object toRemove : batchToRemove) {
remove(toRemove);
}
}
@Override
public <T> T execute(final BucketCallback<T> action) {
try {
return action.doInBucket();
} catch (RuntimeException e) {
throw exceptionTranslator.translateExceptionIfPossible(e);
} catch (TimeoutException e) {
throw new QueryTimeoutException(e.getMessage(), e);
} catch (InterruptedException e) {
throw new OperationInterruptedException(e.getMessage(), e);
} catch (ExecutionException e) {
throw new OperationInterruptedException(e.getMessage(), e);
}
}
@Override
public boolean exists(final String id) {
final String result = execute(new BucketCallback<String>() {
@Override
public String doInBucket() {
return (String) client.get(id);
}
});
return result != null;
/**
* Decode a {@link Document Document&lt;String&gt;} containing a JSON string
* into a {@link CouchbaseStorable}
*/
private CouchbaseStorable decodeAndUnwrap(final Document<String> source, final CouchbaseStorable target) {
return translationService.decode(source.content(), target); //TODO rework and check
}
/**
@@ -277,201 +160,31 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP
}
}
@Override
public CouchbaseConverter getConverter() {
return couchbaseConverter;
}
@Override
public void save(Object objectToSave, final PersistTo persistTo, final ReplicateTo replicateTo) {
ensureNotIterable(objectToSave);
final BeanWrapper<Object> beanWrapper = BeanWrapper.create(objectToSave, couchbaseConverter.getConversionService());
CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(objectToSave.getClass());
final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty();
final Long version = versionProperty != null ? beanWrapper.getProperty(versionProperty, Long.class) : null;
maybeEmitEvent(new BeforeConvertEvent<Object>(objectToSave));
final CouchbaseDocument converted = new CouchbaseDocument();
couchbaseConverter.write(objectToSave, converted);
maybeEmitEvent(new BeforeSaveEvent<Object>(objectToSave, converted));
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
if (version == null) {
OperationFuture<Boolean> setFuture = client.set(converted.getId(), converted.getExpiration(),
translateEncode(converted), persistTo, replicateTo);
boolean future = setFuture.get();
if (!future) {
handleWriteResultError("Saving document failed: " + setFuture.getStatus().getMessage());
}
return future;
} else {
OperationFuture<CASResponse> casFuture = client.asyncCas(converted.getId(), version,
converted.getExpiration(), translateEncode(converted), persistTo, replicateTo);
CASResponse cas = casFuture.get();
if (cas == CASResponse.EXISTS) {
throw new OptimisticLockingFailureException("Saving document with version value failed: " + cas);
} else {
long newCas = casFuture.getCas();
beanWrapper.setProperty(versionProperty, newCas);
return true;
}
}
}
});
maybeEmitEvent(new AfterSaveEvent<Object>(objectToSave, converted));
}
@Override
public void save(Collection<?> batchToSave, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object toSave : batchToSave) {
save(toSave, persistTo, replicateTo);
}
}
@Override
public void insert(Object objectToInsert, final PersistTo persistTo, final ReplicateTo replicateTo) {
ensureNotIterable(objectToInsert);
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(objectToInsert.getClass());
final BeanWrapper<Object> beanWrapper = BeanWrapper.create(objectToInsert, couchbaseConverter.getConversionService());
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
final Long version = beanWrapper.getProperty(persistentEntity.getVersionProperty(), Long.class);
if (version == 0) {
beanWrapper.setProperty(persistentEntity.getVersionProperty(), 0);
}
}
maybeEmitEvent(new BeforeConvertEvent<Object>(objectToInsert));
final CouchbaseDocument converted = new CouchbaseDocument();
couchbaseConverter.write(objectToInsert, converted);
maybeEmitEvent(new BeforeSaveEvent<Object>(objectToInsert, converted));
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
OperationFuture<Boolean> addFuture = client.add(converted.getId(), converted.getExpiration(),
translateEncode(converted), persistTo, replicateTo);
boolean result = addFuture.get();
if(result == false) {
handleWriteResultError("Inserting document failed: "
+ addFuture.getStatus().getMessage());
}
if (result && persistentEntity.hasVersionProperty()) {
beanWrapper.setProperty(persistentEntity.getVersionProperty(), addFuture.getCas());
}
return result;
}
});
maybeEmitEvent(new AfterSaveEvent<Object>(objectToInsert, converted));
}
@Override
public void insert(Collection<?> batchToInsert, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object toInsert : batchToInsert) {
insert(toInsert, persistTo,replicateTo);
}
}
@Override
public void update(Object objectToUpdate, final PersistTo persistTo, final ReplicateTo replicateTo) {
ensureNotIterable(objectToUpdate);
final BeanWrapper<Object> beanWrapper = BeanWrapper.create(objectToUpdate, couchbaseConverter.getConversionService());
CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(objectToUpdate.getClass());
final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty();
final Long version = versionProperty != null ? beanWrapper.getProperty(versionProperty, Long.class) : null;
maybeEmitEvent(new BeforeConvertEvent<Object>(objectToUpdate));
final CouchbaseDocument converted = new CouchbaseDocument();
couchbaseConverter.write(objectToUpdate, converted);
maybeEmitEvent(new BeforeSaveEvent<Object>(objectToUpdate, converted));
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
if (version == null) {
return client.replace(converted.getId(), converted.getExpiration(), translateEncode(converted), persistTo,
replicateTo).get();
} else {
OperationFuture<CASResponse> casFuture = client.asyncCas(converted.getId(), version,
converted.getExpiration(), translateEncode(converted), persistTo, replicateTo);
CASResponse cas = casFuture.get();
if (cas == CASResponse.EXISTS) {
throw new OptimisticLockingFailureException("Updating document with version value failed: " + cas);
} else {
long newCas = casFuture.getCas();
beanWrapper.setProperty(versionProperty, newCas);
return true;
}
}
}
});
maybeEmitEvent(new AfterSaveEvent<Object>(objectToUpdate, converted));
}
@Override
public void update(Collection<?> batchToUpdate, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object toUpdate : batchToUpdate) {
update(toUpdate, persistTo, replicateTo);
}
}
@Override
public void remove(final Object objectToRemove, final PersistTo persistTo, final ReplicateTo replicateTo) {
ensureNotIterable(objectToRemove);
maybeEmitEvent(new BeforeDeleteEvent<Object>(objectToRemove));
if (objectToRemove instanceof String) {
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
return client.delete((String) objectToRemove, persistTo, replicateTo).get();
}
});
maybeEmitEvent(new AfterDeleteEvent<Object>(objectToRemove));
return;
}
final CouchbaseDocument converted = new CouchbaseDocument();
couchbaseConverter.write(objectToRemove, converted);
execute(new BucketCallback<OperationFuture<Boolean>>() {
@Override
public OperationFuture<Boolean> doInBucket() {
return client.delete(converted.getId());
}
});
maybeEmitEvent(new AfterDeleteEvent<Object>(objectToRemove));
}
@Override
public void remove(Collection<?> batchToRemove, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object toRemove : batchToRemove) {
remove(toRemove, persistTo, replicateTo);
}
}
/**
* Handle write errors according to the set {@link #writeResultChecking} setting.
*
* @param message the message to use.
*/
private void handleWriteResultError(String message) {
private void handleWriteResultError(String message, Exception cause) {
if (writeResultChecking == WriteResultChecking.NONE) {
return;
}
if (writeResultChecking == WriteResultChecking.EXCEPTION) {
throw new CouchbaseDataIntegrityViolationException(message);
} else {
LOGGER.error(message);
throw new CouchbaseDataIntegrityViolationException(message, cause);
}
else {
LOGGER.error(message, cause);
}
}
public void setWriteResultChecking(WriteResultChecking writeResultChecking) {
this.writeResultChecking = writeResultChecking == null ? DEFAULT_WRITE_RESULT_CHECKING : writeResultChecking;
}
@Override
public void setApplicationEventPublisher(final ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
/**
@@ -487,7 +200,315 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP
}
@Override
public CouchbaseClient getCouchbaseClient() {
return client;
public void save(Object objectToSave) {
save(objectToSave, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void save(Object objectToSave, PersistTo persistTo, ReplicateTo replicateTo) {
doPersist(objectToSave, persistTo, replicateTo, false, false);
}
@Override
public void save(Collection<?> batchToSave) {
save(batchToSave, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void save(Collection<?> batchToSave, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object o : batchToSave) {
doPersist(o, persistTo, replicateTo, false, false);
}
}
@Override
public void insert(Object objectToInsert) {
insert(objectToInsert, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void insert(Object objectToInsert, PersistTo persistTo, ReplicateTo replicateTo) {
doPersist(objectToInsert, persistTo, replicateTo, true, false);
}
@Override
public void insert(Collection<?> batchToInsert) {
insert(batchToInsert, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void insert(Collection<?> batchToInsert, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object o : batchToInsert) {
doPersist(o, persistTo, replicateTo, true, false);
}
}
@Override
public void update(Object objectToUpdate) {
update(objectToUpdate, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void update(Object objectToUpdate, PersistTo persistTo, ReplicateTo replicateTo) {
doPersist(objectToUpdate, persistTo, replicateTo, false, true);
}
@Override
public void update(Collection<?> batchToUpdate) {
update(batchToUpdate, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void update(Collection<?> batchToUpdate, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object o : batchToUpdate) {
doPersist(o, persistTo, replicateTo, false, true);
}
}
@Override
public <T> T findById(final String id, Class<T> entityClass) {
RawJsonDocument result = execute(new BucketCallback<RawJsonDocument>() {
@Override
public RawJsonDocument doInBucket() {
return client.get(id, RawJsonDocument.class);
}
});
return mapToEntity(id, result, entityClass);
}
@Override
public <T> List<T> findByView(ViewQuery query, Class<T> entityClass) {
query.includeDocs(false);
query.reduce(false);
try {
final ViewResult response = queryView(query);
if (response.error() != null) {
throw new CouchbaseQueryExecutionException("Unable to execute view query due to the following view error: " +
response.error().toString());
}
List<ViewRow> allRows = response.allRows();
final List<T> result = new ArrayList<T>(allRows.size());
for (final ViewRow row : allRows) {
result.add(mapToEntity(row.id(), row.document(RawJsonDocument.class), entityClass));
}
return result;
}
catch (TranscodingException e) {
throw new CouchbaseQueryExecutionException("Unable to execute view query", e);
}
}
@Override
public ViewResult queryView(final ViewQuery query) {
return execute(new BucketCallback<ViewResult>() {
@Override
public ViewResult doInBucket() {
return client.query(query);
}
});
}
@Override
public <T> List<T> findByN1QL(Query n1ql, Class<T> entityClass) {
try {
QueryResult queryResult = queryN1QL(n1ql);
if (queryResult.finalSuccess()) {
List<QueryRow> allRows = queryResult.allRows();
List<T> result = new ArrayList<T>(allRows.size());
for (QueryRow row : allRows) {
String json = row.value().toString();
T decoded = translationService.decodeFragment(json, entityClass);
result.add(decoded);
}
return result;
}
else {
StringBuilder message = new StringBuilder("Unable to execute query due to the following n1ql errors: ");
for (JsonObject error : queryResult.errors()) {
message.append('\n').append(error);
}
throw new CouchbaseQueryExecutionException(message.toString());
}
}
catch (TranscodingException e) {
throw new CouchbaseQueryExecutionException("Unable to execute query", e);
}
}
@Override
public QueryResult queryN1QL(final Query query) {
return execute(new BucketCallback<QueryResult>() {
@Override
public QueryResult doInBucket() throws TimeoutException, ExecutionException, InterruptedException {
return client.query(query);
}
});
}
@Override
public boolean exists(final String id) {
return execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws TimeoutException, ExecutionException, InterruptedException {
return client.exists(id);
}
});
}
@Override
public void remove(Object objectToRemove) {
remove(objectToRemove, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void remove(Object objectToRemove, PersistTo persistTo, ReplicateTo replicateTo) {
doRemove(objectToRemove, persistTo, replicateTo);
}
@Override
public void remove(Collection<?> batchToRemove) {
remove(batchToRemove, PersistTo.NONE, ReplicateTo.NONE);
}
@Override
public void remove(Collection<?> batchToRemove, PersistTo persistTo, ReplicateTo replicateTo) {
for (Object o : batchToRemove) {
doRemove(o, persistTo, replicateTo);
}
}
@Override
public <T> T execute(BucketCallback<T> action) {
try {
return action.doInBucket();
}
catch (RuntimeException e) {
throw exceptionTranslator.translateExceptionIfPossible(e);
}
catch (TimeoutException e) {
throw new QueryTimeoutException(e.getMessage(), e);
}
catch (InterruptedException e) {
throw new OperationInterruptedException(e.getMessage(), e);
}
catch (ExecutionException e) {
throw new OperationInterruptedException(e.getMessage(), e);
}
}
private void doPersist(Object objectToPersist, final PersistTo persistTo, final ReplicateTo replicateTo,
final boolean failOnExist, final boolean failOnMissing) {
ensureNotIterable(objectToPersist);
final String operationDesc = failOnExist ? "Insert" : failOnMissing ? "Update" : "Upsert";
final BeanWrapper<Object> beanWrapper = BeanWrapper.create(objectToPersist, converter.getConversionService());
final CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(objectToPersist.getClass());
final CouchbasePersistentProperty versionProperty = persistentEntity.getVersionProperty();
final Long version = versionProperty != null ? beanWrapper.getProperty(versionProperty, Long.class) : null;
maybeEmitEvent(new BeforeConvertEvent<Object>(objectToPersist));
final CouchbaseDocument converted = new CouchbaseDocument();
converter.write(objectToPersist, converted);
maybeEmitEvent(new BeforeSaveEvent<Object>(objectToPersist, converted));
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
Document<String> doc = encodeAndWrap(converted, version);
Document<String> storedDoc;
try {
if (!failOnExist && !failOnMissing) {
storedDoc = client.upsert(doc, persistTo, replicateTo);
}
else if (failOnMissing) {
storedDoc = client.replace(doc, persistTo, replicateTo);
}
else {
storedDoc = client.insert(doc, persistTo, replicateTo);
}
if (persistentEntity.hasVersionProperty() && storedDoc != null && storedDoc.cas() != 0) {
//inject new cas into the bean
beanWrapper.setProperty(versionProperty, storedDoc.cas());
return true;
}
return false;
}
catch (CASMismatchException e) {
throw new OptimisticLockingFailureException(operationDesc +
" document with version value failed: " + version);
}
catch (Exception e) {
handleWriteResultError(operationDesc + " document failed: " + e.getMessage(), e);
return false; //this could be skipped if WriteResultChecking.EXCEPTION
}
}
});
maybeEmitEvent(new AfterSaveEvent<Object>(objectToPersist, converted));
}
private void doRemove(final Object objectToRemove, final PersistTo persistTo, final ReplicateTo replicateTo) {
ensureNotIterable(objectToRemove);
maybeEmitEvent(new BeforeDeleteEvent<Object>(objectToRemove));
if (objectToRemove instanceof String) {
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() throws InterruptedException, ExecutionException {
RawJsonDocument deletedDoc = client.remove((String) objectToRemove, persistTo, replicateTo,
RawJsonDocument.class);
return deletedDoc != null;
}
});
maybeEmitEvent(new AfterDeleteEvent<Object>(objectToRemove));
return;
}
final CouchbaseDocument converted = new CouchbaseDocument();
converter.write(objectToRemove, converted);
execute(new BucketCallback<Boolean>() {
@Override
public Boolean doInBucket() {
RawJsonDocument deletedDoc = client.remove(converted.getId(), persistTo, replicateTo
, RawJsonDocument.class);
return deletedDoc != null;
}
});
maybeEmitEvent(new AfterDeleteEvent<Object>(objectToRemove));
}
private <T> T mapToEntity(String id, Document<String> data, Class<T> entityClass) {
if (data == null) {
return null;
}
final CouchbaseDocument converted = new CouchbaseDocument(id);
Object readEntity = converter.read(entityClass, (CouchbaseDocument) decodeAndUnwrap(data, converted));
final BeanWrapper<Object> beanWrapper = BeanWrapper.create(readEntity, converter.getConversionService());
CouchbasePersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(readEntity.getClass());
if (persistentEntity.hasVersionProperty()) {
beanWrapper.setProperty(persistentEntity.getVersionProperty(), data.cas());
}
return (T) readEntity;
}
@Override
public Bucket getCouchbaseBucket() {
return this.client;
}
@Override
public CouchbaseConverter getConverter() {
return this.converter;
}
}

View File

@@ -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,
@@ -27,6 +27,7 @@ public class OperationCancellationException extends TransientDataAccessException
/**
* Constructor for OperationCancellationException.
*
* @param msg the detail message
*/
public OperationCancellationException(final String msg) {
@@ -35,6 +36,7 @@ public class OperationCancellationException extends TransientDataAccessException
/**
* Constructor for OperationCancellationException.
*
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/

View File

@@ -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,
@@ -27,6 +27,7 @@ public class OperationInterruptedException extends TransientDataAccessException
/**
* Constructor for OperationInterruptedException.
*
* @param msg the detail message
*/
public OperationInterruptedException(final String msg) {
@@ -35,6 +36,7 @@ public class OperationInterruptedException extends TransientDataAccessException
/**
* Constructor for OperationInterruptedException.
*
* @param msg the detail message
* @param cause the root cause from the data access API in use
*/

View File

@@ -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,

View File

@@ -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,

View File

@@ -1,11 +1,11 @@
/*
* Copyright 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,
@@ -86,7 +86,7 @@ class ConverterRegistration {
}
/**
* Returns whether the source type is a Mongo simple one.
* Returns whether the source type is a Couchbase simple one.
*
* @return
*/
@@ -95,7 +95,7 @@ class ConverterRegistration {
}
/**
* Returns whether the target type is a Mongo simple one.
* Returns whether the target type is a Couchbase simple one.
*
* @return
*/
@@ -104,7 +104,7 @@ class ConverterRegistration {
}
/**
* Returns whether the given type is a type that Mongo can handle basically.
* Returns whether the given type is a type that Couchbase can handle basically.
*
* @param type
* @return

View File

@@ -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,
@@ -28,8 +28,8 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProper
* @author Michael Nitschinger
*/
public interface CouchbaseConverter
extends EntityConverter<CouchbasePersistentEntity<?>,
CouchbasePersistentProperty, Object, CouchbaseDocument>,
CouchbaseWriter<Object, CouchbaseDocument>,
EntityReader<Object, CouchbaseDocument> {
extends EntityConverter<CouchbasePersistentEntity<?>,
CouchbasePersistentProperty, Object, CouchbaseDocument>,
CouchbaseWriter<Object, CouchbaseDocument>,
EntityReader<Object, CouchbaseDocument> {
}

View File

@@ -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,13 @@
package org.springframework.data.couchbase.core.convert;
import java.util.Map;
import org.springframework.context.expression.MapAccessor;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import java.util.Map;
/**
* A property accessor for document properties.
*

View File

@@ -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,

View File

@@ -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,
@@ -24,5 +24,5 @@ import org.springframework.data.convert.EntityWriter;
* @author Michael Nitschinger
*/
public interface CouchbaseWriter<T, ConvertedCouchbaseDocument> extends
EntityWriter<T, ConvertedCouchbaseDocument> {
EntityWriter<T, ConvertedCouchbaseDocument> {
}

View File

@@ -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,26 +16,30 @@
package org.springframework.data.couchbase.core.convert;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.JodaTimeConverters;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.util.Assert;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Value object to capture custom conversion.
*
* <p/>
* <p>Types that can be mapped directly onto JSON are considered simple ones, because they neither need deeper
* inspection nor nested conversion.</p>
*
@@ -69,6 +73,7 @@ public class CustomConversions {
/**
* Create a new instance with a given list of conversers.
*
* @param converters the list of custom converters.
*/
public CustomConversions(final List<?> converters) {
@@ -155,10 +160,12 @@ public class CustomConversions {
for (GenericConverter.ConvertiblePair pair : genericConverter.getConvertibleTypes()) {
register(new ConverterRegistration(pair, isReading, isWriting));
}
} else if (converter instanceof Converter) {
}
else if (converter instanceof Converter) {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
register(new ConverterRegistration(arguments[0], arguments[1], isReading, isWriting));
} else {
}
else {
throw new IllegalArgumentException("Unsupported Converter type!");
}
}
@@ -279,7 +286,7 @@ public class CustomConversions {
}
/**
* Inspects the given {@link org.springframework.core.convert.converter.GenericConverter.ConvertiblePair} for ones
* Inspects the given {@link GenericConverter.ConvertiblePair} for ones
* that have a source compatible type as source. Additionally checks assignability of the target type if one is
* given.
*
@@ -289,7 +296,7 @@ public class CustomConversions {
* @return
*/
private static Class<?> getCustomTarget(Class<?> sourceType, Class<?> requestedTargetType,
Iterable<GenericConverter.ConvertiblePair> pairs) {
Iterable<GenericConverter.ConvertiblePair> pairs) {
Assert.notNull(sourceType);
Assert.notNull(pairs);

View File

@@ -1,11 +1,11 @@
/*
* Copyright 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,21 +16,22 @@
package org.springframework.data.couchbase.core.convert;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.util.ClassUtils;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.util.ClassUtils;
/**
* Out of the box conversions for java dates and calendars.
*
@@ -38,7 +39,8 @@ import java.util.List;
*/
public final class DateConverters {
private DateConverters() {}
private DateConverters() {
}
private static final boolean JODA_TIME_IS_PRESENT = ClassUtils.isPresent("org.joda.time.LocalDate", null);
@@ -85,7 +87,7 @@ public final class DateConverters {
@Override
public Long convert(Calendar source) {
return source == null ? null : source.getTimeInMillis() / 1000;
return source == null ? null : source.getTimeInMillis() / 1000;
}
}

View File

@@ -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,

View File

@@ -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,6 +16,13 @@
package org.springframework.data.couchbase.core.convert;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.CollectionFactory;
@@ -31,14 +38,20 @@ import org.springframework.data.mapping.AssociationHandler;
import org.springframework.data.mapping.PreferredConstructor.Parameter;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.*;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SpELContext;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import java.util.*;
/**
* A mapping converter for Couchbase.
*
@@ -154,7 +167,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
protected <R> R read(final CouchbasePersistentEntity<R> entity, final CouchbaseDocument source, final Object parent) {
final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(source, spELContext);
ParameterValueProvider<CouchbasePersistentProperty> provider =
getParameterProvider(entity, source, evaluator, parent);
getParameterProvider(entity, source, evaluator, parent);
EntityInstantiator instantiator = instantiators.getInstantiatorFor(entity);
R instance = instantiator.createInstance(entity, provider);
@@ -197,7 +210,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* @return the actual property value.
*/
protected Object getValueInternal(final CouchbasePersistentProperty property, final CouchbaseDocument source,
final Object parent) {
final Object parent) {
return new CouchbasePropertyValueProvider(source, spELContext, parent).getPropertyValue(property);
}
@@ -211,14 +224,14 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* @return a new parameter value provider.
*/
private ParameterValueProvider<CouchbasePersistentProperty> getParameterProvider(
final CouchbasePersistentEntity<?> entity, final CouchbaseDocument source,
final DefaultSpELExpressionEvaluator evaluator, final Object parent) {
final CouchbasePersistentEntity<?> entity, final CouchbaseDocument source,
final DefaultSpELExpressionEvaluator evaluator, final Object parent) {
CouchbasePropertyValueProvider provider = new CouchbasePropertyValueProvider(source, evaluator, parent);
PersistentEntityParameterValueProvider<CouchbasePersistentProperty> parameterProvider =
new PersistentEntityParameterValueProvider<CouchbasePersistentProperty>(entity, provider, parent);
new PersistentEntityParameterValueProvider<CouchbasePersistentProperty>(entity, provider, parent);
return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider,
parent);
parent);
}
/**
@@ -231,7 +244,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
*/
@SuppressWarnings("unchecked")
protected Map<Object, Object> readMap(final TypeInformation<?> type, final CouchbaseDocument source,
final Object parent) {
final Object parent) {
Assert.notNull(source);
Class<?> mapType = typeMapper.readType(source, type).getType();
@@ -368,7 +381,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* @param entity the persistent entity to convert from.
*/
protected void writeInternal(final Object source, final CouchbaseDocument target,
final CouchbasePersistentEntity<?> entity) {
final CouchbasePersistentEntity<?> entity) {
if (source == null) {
return;
}
@@ -377,7 +390,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
throw new MappingException("No mapping metadata found for entity of type " + source.getClass().getName());
}
final BeanWrapper<Object> wrapper = BeanWrapper.create(source, conversionService);
final BeanWrapper<Object> wrapper = BeanWrapper.create(source, conversionService);
final CouchbasePersistentProperty idProperty = entity.getIdProperty();
final CouchbasePersistentProperty versionProperty = entity.getVersionProperty();
@@ -428,7 +441,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
*/
@SuppressWarnings("unchecked")
private void writePropertyInternal(final Object source, final CouchbaseDocument target,
final CouchbasePersistentProperty prop) {
final CouchbasePersistentProperty prop) {
if (source == null) {
return;
}
@@ -459,7 +472,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
addCustomTypeKeyIfNecessary(type, source, propertyDoc);
CouchbasePersistentEntity<?> entity = isSubtype(prop.getType(), source.getClass()) ? mappingContext
.getPersistentEntity(source.getClass()) : mappingContext.getPersistentEntity(type);
.getPersistentEntity(source.getClass()) : mappingContext.getPersistentEntity(type);
writeInternal(source, propertyDoc, entity);
target.put(name, propertyDoc);
}
@@ -487,7 +500,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* @return the written couchbase document.
*/
private CouchbaseDocument writeMapInternal(final Map<Object, Object> source, final CouchbaseDocument target,
final TypeInformation<?> type) {
final TypeInformation<?> type) {
for (Map.Entry<Object, Object> entry : source.entrySet()) {
Object key = entry.getKey();
Object val = entry.getValue();
@@ -533,7 +546,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* @return the created couchbase list.
*/
private CouchbaseList writeCollectionInternal(final Collection<?> source, final CouchbaseList target,
final TypeInformation<?> type) {
final TypeInformation<?> type) {
TypeInformation<?> componentType = type == null ? null : type.getComponentType();
for (Object element : source) {
@@ -573,7 +586,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<Object>() : CollectionFactory
.createCollection(collectionType, source.size(false));
.createCollection(collectionType, source.size(false));
TypeInformation<?> componentType = targetType.getComponentType();
Class<?> rawComponentType = componentType == null ? null : componentType.getType();
@@ -709,12 +722,12 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
private final Object parent;
public CouchbasePropertyValueProvider(final CouchbaseDocument source, final SpELContext factory,
final Object parent) {
final Object parent) {
this(source, new DefaultSpELExpressionEvaluator(source, factory), parent);
}
public CouchbasePropertyValueProvider(final CouchbaseDocument source,
final DefaultSpELExpressionEvaluator evaluator, final Object parent) {
final DefaultSpELExpressionEvaluator evaluator, final Object parent) {
Assert.notNull(source);
Assert.notNull(evaluator);
@@ -744,7 +757,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
* A expression parameter value provider.
*/
private class ConverterAwareSpELExpressionParameterValueProvider extends
SpELExpressionParameterValueProvider<CouchbasePersistentProperty> {
SpELExpressionParameterValueProvider<CouchbasePersistentProperty> {
private final Object parent;
@@ -757,7 +770,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter
@Override
protected <T> T potentiallyConvertSpelValue(final Object object,
final Parameter<T, CouchbasePersistentProperty> parameter) {
final Parameter<T, CouchbasePersistentProperty> parameter) {
return readValue(object, parameter.getType(), parent);
}
}

View File

@@ -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,12 +16,18 @@
package org.springframework.data.couchbase.core.convert.translation;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbaseList;
@@ -29,9 +35,6 @@ import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.io.*;
import java.util.Map;
/**
* A Jackson JSON Translator that implements the {@link TranslationService} contract.
*
@@ -58,11 +61,10 @@ public class JacksonTranslationService implements TranslationService, Initializi
* Encode a {@link CouchbaseStorable} to a JSON string.
*
* @param source the source document to encode.
*
* @return the encoded JSON String.
*/
@Override
public final Object encode(final CouchbaseStorable source) {
public final String encode(final CouchbaseStorable source) {
Writer writer = new StringWriter();
try {
@@ -70,7 +72,8 @@ public class JacksonTranslationService implements TranslationService, Initializi
encodeRecursive(source, generator);
generator.close();
writer.close();
} catch (IOException ex) {
}
catch (IOException ex) {
throw new RuntimeException("Could not encode JSON", ex);
}
@@ -82,7 +85,6 @@ public class JacksonTranslationService implements TranslationService, Initializi
*
* @param source the source document
* @param generator the JSON generator.
*
* @throws IOException
*/
private void encodeRecursive(final CouchbaseStorable source, final JsonGenerator generator) throws IOException {
@@ -101,7 +103,8 @@ public class JacksonTranslationService implements TranslationService, Initializi
if (simpleTypeHolder.isSimpleType(clazz) && !isEnumOrClass(clazz)) {
generator.writeObject(value);
} else {
}
else {
objectMapper.writeValue(generator, value);
}
@@ -119,11 +122,10 @@ public class JacksonTranslationService implements TranslationService, Initializi
*
* @param source the source formatted document.
* @param target the target of the populated data.
*
* @return the decoded structure.
*/
@Override
public final CouchbaseStorable decode(final Object source, final CouchbaseStorable target) {
public final CouchbaseStorable decode(final String source, final CouchbaseStorable target) {
try {
JsonParser parser = factory.createParser((String) source);
while (parser.nextToken() != null) {
@@ -131,14 +133,17 @@ public class JacksonTranslationService implements TranslationService, Initializi
if (currentToken == JsonToken.START_OBJECT) {
return decodeObject(parser, (CouchbaseDocument) target);
} else if (currentToken == JsonToken.START_ARRAY) {
}
else if (currentToken == JsonToken.START_ARRAY) {
return decodeArray(parser, new CouchbaseList());
} else {
}
else {
throw new MappingException("JSON to decode needs to start as array or object!");
}
}
parser.close();
} catch (IOException ex) {
}
catch (IOException ex) {
throw new RuntimeException("Could not decode JSON", ex);
}
return target;
@@ -149,7 +154,6 @@ public class JacksonTranslationService implements TranslationService, Initializi
*
* @param parser the JSON parser with the content.
* @param target the target where the content should be stored.
*
* @throws IOException
* @returns the decoded object.
*/
@@ -160,11 +164,14 @@ public class JacksonTranslationService implements TranslationService, Initializi
while (currentToken != null && currentToken != JsonToken.END_OBJECT) {
if (currentToken == JsonToken.START_OBJECT) {
target.put(fieldName, decodeObject(parser, new CouchbaseDocument()));
} else if (currentToken == JsonToken.START_ARRAY) {
}
else if (currentToken == JsonToken.START_ARRAY) {
target.put(fieldName, decodeArray(parser, new CouchbaseList()));
} else if (currentToken == JsonToken.FIELD_NAME) {
}
else if (currentToken == JsonToken.FIELD_NAME) {
fieldName = parser.getCurrentName();
} else {
}
else {
target.put(fieldName, decodePrimitive(currentToken, parser));
}
@@ -179,7 +186,6 @@ public class JacksonTranslationService implements TranslationService, Initializi
*
* @param parser the JSON parser with the content.
* @param target the target where the content should be stored.
*
* @throws IOException
* @returns the decoded list.
*/
@@ -189,9 +195,11 @@ public class JacksonTranslationService implements TranslationService, Initializi
while (currentToken != null && currentToken != JsonToken.END_ARRAY) {
if (currentToken == JsonToken.START_OBJECT) {
target.put(decodeObject(parser, new CouchbaseDocument()));
} else if (currentToken == JsonToken.START_ARRAY) {
}
else if (currentToken == JsonToken.START_ARRAY) {
target.put(decodeArray(parser, new CouchbaseList()));
} else {
}
else {
target.put(decodePrimitive(currentToken, parser));
}
@@ -206,9 +214,7 @@ public class JacksonTranslationService implements TranslationService, Initializi
*
* @param token the type of token.
* @param parser the parser with the content.
*
* @return the decoded primitve.
*
* @throws IOException
*/
private Object decodePrimitive(final JsonToken token, final JsonParser parser) throws IOException {
@@ -221,7 +227,8 @@ public class JacksonTranslationService implements TranslationService, Initializi
case VALUE_NUMBER_INT:
try {
return parser.getValueAsInt();
} catch (final JsonParseException e) {
}
catch (final JsonParseException e) {
return parser.getValueAsLong();
}
case VALUE_NUMBER_FLOAT:
@@ -229,7 +236,17 @@ public class JacksonTranslationService implements TranslationService, Initializi
case VALUE_NULL:
return null;
default:
throw new MappingException("Could not decode primitve value " + token);
throw new MappingException("Could not decode primitive value " + token);
}
}
@Override
public <T> T decodeFragment(String source, Class<T> target) {
try {
return objectMapper.readValue(source, target);
}
catch (IOException e) {
throw new RuntimeException("Cannot decode ad-hoc JSON", e);
}
}

View File

@@ -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,8 @@
package org.springframework.data.couchbase.core.convert.translation;
import com.couchbase.client.java.query.QueryRow;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
@@ -27,12 +29,12 @@ import org.springframework.data.couchbase.core.mapping.CouchbaseStorable;
public interface TranslationService {
/**
* Encodes a {@link CouchbaseDocument} into the target format.
* Encodes a JSON String into the target format.
*
* @param source the source document to encode.
* @param source the source contents to encode.
* @return the encoded document representation.
*/
Object encode(CouchbaseStorable source);
String encode(CouchbaseStorable source);
/**
* Decodes the target format into a {@link CouchbaseDocument}
@@ -41,5 +43,15 @@ public interface TranslationService {
* @param target the target of the populated data.
* @return a properly populated document to work with.
*/
CouchbaseStorable decode(Object source, CouchbaseStorable target);
CouchbaseStorable decode(String source, CouchbaseStorable target);
/**
* Decodes an ad-hoc JSON object into a corresponding "case" class.
*
* @param source the JSON for the ad-hoc JSON object (from a N1QL {@link QueryRow} for instance).
* @param target the target class information.
* @param <T> the target class.
* @return an ad-hoc instance of the decoded JSON into the corresponding "case" class.
*/
<T> T decodeFragment(String source, Class<T> target);
}

View File

@@ -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,
@@ -31,7 +31,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
* @author Michael Nitschinger
*/
public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T, CouchbasePersistentProperty>
implements CouchbasePersistentEntity<T>, ApplicationContextAware {
implements CouchbasePersistentEntity<T>, ApplicationContextAware {
/**
* Contains the evaluation context.
@@ -40,6 +40,7 @@ public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T,
/**
* Create a new entity.
*
* @param typeInformation the type information of the entity.
*/
public BasicCouchbasePersistentEntity(final TypeInformation<T> typeInformation) {
@@ -55,9 +56,9 @@ public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T,
*/
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
}
/**
@@ -66,9 +67,9 @@ public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T,
* @return the expiration time.
*/
public int getExpiry() {
org.springframework.data.couchbase.core.mapping.Document annotation =
getType().getAnnotation(org.springframework.data.couchbase.core.mapping.Document.class);
org.springframework.data.couchbase.core.mapping.Document annotation =
getType().getAnnotation(org.springframework.data.couchbase.core.mapping.Document.class);
return annotation == null ? 0 : annotation.expiry();
}
}

View File

@@ -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.core.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.FieldNamingStrategy;
@@ -24,20 +27,17 @@ import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
/**
* Implements annotated property representations of a given Field instance.
*
* <p/>
* <p>This object is used to gather information out of properties on objects that need to be persisted. For example, it
* supports overriding of the actual property name by providing custom annotations.</p>
*
* @author Michael Nitschinger
*/
public class BasicCouchbasePersistentProperty
extends AnnotationBasedPersistentProperty<CouchbasePersistentProperty>
implements CouchbasePersistentProperty {
extends AnnotationBasedPersistentProperty<CouchbasePersistentProperty>
implements CouchbasePersistentProperty {
private final FieldNamingStrategy fieldNamingStrategy;
@@ -50,11 +50,11 @@ public class BasicCouchbasePersistentProperty
* @param simpleTypeHolder the type holder.
*/
public BasicCouchbasePersistentProperty(final Field field, final PropertyDescriptor propertyDescriptor,
final CouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder,
final FieldNamingStrategy fieldNamingStrategy) {
final CouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder,
final FieldNamingStrategy fieldNamingStrategy) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
this.fieldNamingStrategy = fieldNamingStrategy == null ? PropertyNameFieldNamingStrategy.INSTANCE
: fieldNamingStrategy;
: fieldNamingStrategy;
}
/**
@@ -67,14 +67,14 @@ public class BasicCouchbasePersistentProperty
/**
* Returns the field name of the property.
*
* <p/>
* The field name can be different from the actual property name by using a
* custom annotation.
*/
@Override
public String getFieldName() {
org.springframework.data.couchbase.core.mapping.Field annotation = getField().
getAnnotation(org.springframework.data.couchbase.core.mapping.Field.class);
getAnnotation(org.springframework.data.couchbase.core.mapping.Field.class);
if (annotation != null && StringUtils.hasText(annotation.value())) {
return annotation.value();
@@ -84,7 +84,7 @@ public class BasicCouchbasePersistentProperty
if (!StringUtils.hasText(fieldName)) {
throw new MappingException(String.format("Invalid (null or empty) field name returned for property %s by %s!",
this, fieldNamingStrategy.getClass()));
this, fieldNamingStrategy.getClass()));
}
return fieldName;

View File

@@ -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,20 +16,20 @@
package org.springframework.data.couchbase.core.mapping;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.data.mapping.model.SimpleTypeHolder;
/**
* A {@link CouchbaseDocument} is an abstract representation of a document stored inside Couchbase Server.
*
* <p/>
* <p>It acts like a {@link HashMap}, but only allows those types to be written that are supported by the underlying
* storage format, which is currently JSON. Note that JSON conversion is not happening here, but performed at a
* different stage based on the payload stored in the {@link CouchbaseDocument}.</p>
*
* <p/>
* <p>In addition to the actual content, meta data is also stored. This especially refers to the document ID and its
* expiration time. Note that this information is not mandatory, since documents can be nested and therefore only the
* topmost document most likely has an ID.</p>
@@ -115,7 +115,7 @@ public class CouchbaseDocument implements CouchbaseStorable {
*
* @param key the key of the attribute.
* @return the value to which the specified key is mapped, or
* null if does not contain a mapping for the key.
* null if does not contain a mapping for the key.
*/
public final Object get(final String key) {
return payload.get(key);
@@ -123,7 +123,7 @@ public class CouchbaseDocument implements CouchbaseStorable {
/**
* Returns the current payload, including all recursive elements.
*
* <p/>
* It either returns the raw results or makes sure that the recusrive elements
* are also exported properly.
*
@@ -134,7 +134,8 @@ public class CouchbaseDocument implements CouchbaseStorable {
for (Map.Entry<String, Object> entry : payload.entrySet()) {
if (entry.getValue() instanceof CouchbaseDocument) {
toExport.put(entry.getKey(), ((CouchbaseDocument) entry.getValue()).export());
} else if (entry.getValue() instanceof CouchbaseList) {
}
else if (entry.getValue() instanceof CouchbaseList) {
toExport.put(entry.getKey(), ((CouchbaseList) entry.getValue()).export());
}
}
@@ -187,7 +188,8 @@ public class CouchbaseDocument implements CouchbaseStorable {
for (Object value : payload.values()) {
if (value instanceof CouchbaseDocument) {
totalSize += ((CouchbaseDocument) value).size(true);
} else if (value instanceof CouchbaseList) {
}
else if (value instanceof CouchbaseList) {
totalSize += ((CouchbaseList) value).size(true);
}
}
@@ -197,7 +199,7 @@ public class CouchbaseDocument implements CouchbaseStorable {
/**
* Returns the underlying payload.
*
* <p/>
* <p>Note that unlike {@link #export()}, the nested objects are not converted, so the "raw" map is returned.</p>
*
* @return the underlying payload.
@@ -208,7 +210,7 @@ public class CouchbaseDocument implements CouchbaseStorable {
/**
* Returns the expiration time of the document.
*
* <p/>
* If the expiration time is 0, then the document will be persisted until
* deleted manually ("forever").
*
@@ -220,7 +222,7 @@ public class CouchbaseDocument implements CouchbaseStorable {
/**
* Set the expiration time of the document.
*
* <p/>
* If the expiration time is 0, then the document will be persisted until
* deleted manually ("forever").
*
@@ -255,19 +257,19 @@ public class CouchbaseDocument implements CouchbaseStorable {
/**
* Verifies that only values of a certain and supported type
* can be stored.
*
* <p/>
* <p>If this is not the case, a {@link IllegalArgumentException} is
* thrown.</p>
*
* @param value the object to verify its type.
*/
private void verifyValueType(final Object value) {
if(value == null) {
if (value == null) {
return;
}
final Class<?> clazz = value.getClass();
if (simpleTypeHolder.isSimpleType(clazz)) {
return;
return;
}
throw new IllegalArgumentException("Attribute of type " + clazz.getCanonicalName() + " cannot be stored and must be converted.");
}
@@ -280,9 +282,9 @@ public class CouchbaseDocument implements CouchbaseStorable {
@Override
public String toString() {
return "CouchbaseDocument{" +
"id=" + id +
", exp=" + expiration +
", payload=" + payload +
'}';
"id=" + id +
", exp=" + expiration +
", payload=" + payload +
'}';
}
}

View File

@@ -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,16 +16,16 @@
package org.springframework.data.couchbase.core.mapping;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.data.mapping.model.SimpleTypeHolder;
/**
* A {@link CouchbaseList} is an abstract list that represents an array stored in a (most of the times JSON) document.
*
* <p/>
* <p>This {@link CouchbaseList} is part of the potentially nested structure inside one or more
* {@link CouchbaseDocument}s. It can also contain them recursively, depending on how the document is modeled.</p>
*/
@@ -78,9 +78,10 @@ public class CouchbaseList implements CouchbaseStorable {
additionalTypes.add(CouchbaseDocument.class);
additionalTypes.add(CouchbaseList.class);
if (simpleTypeHolder != null) {
this.simpleTypeHolder = new SimpleTypeHolder(additionalTypes, simpleTypeHolder);
} else {
this.simpleTypeHolder = new SimpleTypeHolder(additionalTypes, true);
this.simpleTypeHolder = new SimpleTypeHolder(additionalTypes, simpleTypeHolder);
}
else {
this.simpleTypeHolder = new SimpleTypeHolder(additionalTypes, true);
}
}
@@ -133,7 +134,8 @@ public class CouchbaseList implements CouchbaseStorable {
for (Object value : payload) {
if (value instanceof CouchbaseDocument) {
totalSize += ((CouchbaseDocument) value).size(true);
} else if (value instanceof CouchbaseList) {
}
else if (value instanceof CouchbaseList) {
totalSize += ((CouchbaseList) value).size(true);
}
}
@@ -143,7 +145,7 @@ public class CouchbaseList implements CouchbaseStorable {
/**
* Returns the current payload, including all recursive elements.
*
* <p/>
* It either returns the raw results or makes sure that the recusrive elements
* are also exported properly.
*
@@ -157,7 +159,8 @@ public class CouchbaseList implements CouchbaseStorable {
if (entry instanceof CouchbaseDocument) {
toExport.remove(elem);
toExport.add(elem, ((CouchbaseDocument) entry).export());
} else if (entry instanceof CouchbaseList) {
}
else if (entry instanceof CouchbaseList) {
toExport.remove(elem);
toExport.add(elem, ((CouchbaseList) entry).export());
}
@@ -188,14 +191,14 @@ public class CouchbaseList implements CouchbaseStorable {
/**
* Verifies that only values of a certain and supported type
* can be stored.
*
* <p/>
* <p>If this is not the case, a {@link IllegalArgumentException} is
* thrown.</p>
*
* @param value the object to verify its type.
*/
private void verifyValueType(final Object value) {
if(value == null) {
if (value == null) {
return;
}
@@ -205,7 +208,7 @@ public class CouchbaseList implements CouchbaseStorable {
}
throw new IllegalArgumentException("Attribute of type "
+ clazz.getCanonicalName() + "can not be stored and must be converted.");
+ clazz.getCanonicalName() + "can not be stored and must be converted.");
}
/**
@@ -216,7 +219,7 @@ public class CouchbaseList implements CouchbaseStorable {
@Override
public String toString() {
return "CouchbaseList{" +
"payload=" + payload +
'}';
"payload=" + payload +
'}';
}
}

View File

@@ -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.core.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -25,9 +28,6 @@ import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
/**
* Default implementation of a {@link org.springframework.data.mapping.context.MappingContext} for Couchbase using
* {@link BasicCouchbasePersistentEntity} and {@link BasicCouchbasePersistentProperty} as primary abstractions.
@@ -35,8 +35,8 @@ import java.lang.reflect.Field;
* @author Michael Nitschinger
*/
public class CouchbaseMappingContext
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
implements ApplicationContextAware {
extends AbstractMappingContext<BasicCouchbasePersistentEntity<?>, CouchbasePersistentProperty>
implements ApplicationContextAware {
/**
* Contains the application context to configure the application.
@@ -58,7 +58,7 @@ public class CouchbaseMappingContext
* Defaults to a strategy using the plain property name.
*
* @param fieldNamingStrategy the {@link FieldNamingStrategy} to be used to determine the field name if no manual
* mapping is applied.
* mapping is applied.
*/
public void setFieldNamingStrategy(final FieldNamingStrategy fieldNamingStrategy) {
this.fieldNamingStrategy = fieldNamingStrategy == null ? DEFAULT_NAMING_STRATEGY : fieldNamingStrategy;
@@ -91,7 +91,7 @@ public class CouchbaseMappingContext
*/
@Override
protected CouchbasePersistentProperty createPersistentProperty(final Field field, final PropertyDescriptor descriptor,
final BasicCouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder) {
final BasicCouchbasePersistentEntity<?> owner, final SimpleTypeHolder simpleTypeHolder) {
return new BasicCouchbasePersistentProperty(field, descriptor, owner, simpleTypeHolder, fieldNamingStrategy);
}
@@ -101,9 +101,9 @@ public class CouchbaseMappingContext
* @param applicationContext the application context to be assigned.
* @throws BeansException if the context can not be set properly.
*/
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}

View File

@@ -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,
@@ -24,13 +24,13 @@ import org.springframework.data.mapping.PersistentEntity;
* @author Michael Nitschinger
*/
public interface CouchbasePersistentEntity<T> extends
PersistentEntity<T, CouchbasePersistentProperty> {
PersistentEntity<T, CouchbasePersistentProperty> {
/**
* Returns the expiry time for the document.
*
* @return the expiration time.
*/
int getExpiry();
int getExpiry();
}

View File

@@ -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,
@@ -27,7 +27,7 @@ public interface CouchbasePersistentProperty extends PersistentProperty<Couchbas
/**
* Returns the field name of the property.
*
* <p/>
* The field name can be different from the actual property name by using a custom annotation.
*/
String getFieldName();

View File

@@ -1,18 +1,37 @@
/*
* 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.mapping;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.couchbase.client.java.document.RawJsonDocument;
import com.couchbase.client.java.document.json.JsonArray;
import org.springframework.data.mapping.model.SimpleTypeHolder;
public abstract class CouchbaseSimpleTypes {
static {
Set<Class<?>> simpleTypes = new HashSet<Class<?>>();
simpleTypes.add(CouchbaseDocument.class);
simpleTypes.add(CouchbaseList.class);
simpleTypes.add(RawJsonDocument.class);
simpleTypes.add(JsonArray.class);
COUCHBASE_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes);
}

View File

@@ -1,8 +1,24 @@
/*
* 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.mapping;
/**
* Marker Interface to identify either a {@link CouchbaseDocument} or a {@link CouchbaseList}.
*
* <p/>
* This interface will be extended in the future to refactor the needed infrastructure into the common interface.
*
* @author Michael Nitschinger

View File

@@ -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,9 +16,13 @@
package org.springframework.data.couchbase.core.mapping;
import org.springframework.data.annotation.Persistent;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
import org.springframework.data.annotation.Persistent;
/**
* Identifies a domain object to be persisted to Couchbase.
@@ -28,9 +32,9 @@ import java.lang.annotation.*;
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Target({ElementType.TYPE})
public @interface Document {
/**
* An optional expiry time for the document.
*/

View File

@@ -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,

View File

@@ -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,
@@ -18,6 +18,7 @@ package org.springframework.data.couchbase.core.mapping.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.core.GenericTypeResolver;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
@@ -42,25 +43,28 @@ public class AbstractCouchbaseEventListener<E> implements ApplicationListener<Co
@SuppressWarnings("rawtypes")
public void onApplicationEvent(CouchbaseMappingEvent<?> event) {
E source = (E) event.getSource();
// Check for matching domain type and invoke callbacks
if (source != null && !domainClass.isAssignableFrom(source.getClass())) {
return;
}
E source = (E) event.getSource();
// Check for matching domain type and invoke callbacks
if (source != null && !domainClass.isAssignableFrom(source.getClass())) {
return;
}
if (event instanceof BeforeDeleteEvent) {
onBeforeDelete(event.getSource(), event.getDocument());
return;
} else if (event instanceof AfterDeleteEvent) {
}
else if (event instanceof AfterDeleteEvent) {
onAfterDelete(event.getSource(), event.getDocument());
return;
}
if (event instanceof BeforeConvertEvent) {
onBeforeConvert(source);
} else if (event instanceof BeforeSaveEvent) {
}
else if (event instanceof BeforeSaveEvent) {
onBeforeSave(source, event.getDocument());
} else if (event instanceof AfterSaveEvent) {
}
else if (event instanceof AfterSaveEvent) {
onAfterSave(source, event.getDocument());
}
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,
@@ -18,6 +18,7 @@ package org.springframework.data.couchbase.core.mapping.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
@@ -31,10 +32,14 @@ public class LoggingEventListener extends AbstractCouchbaseEventListener<Object>
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingEventListener.class);
@Override
public void onBeforeDelete(Object source, CouchbaseDocument doc) { LOGGER.info("onBeforeDelete: {}, {}", source, doc); }
public void onBeforeDelete(Object source, CouchbaseDocument doc) {
LOGGER.info("onBeforeDelete: {}, {}", source, doc);
}
@Override
public void onAfterDelete(Object source, CouchbaseDocument doc) { LOGGER.info("onAfterDelete: {} {}", source, doc); }
public void onAfterDelete(Object source, CouchbaseDocument doc) {
LOGGER.info("onAfterDelete: {} {}", source, doc);
}
@Override
public void onAfterSave(Object source, CouchbaseDocument doc) {

View File

@@ -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,14 +16,16 @@
package org.springframework.data.couchbase.core.mapping.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.util.Assert;
import java.util.Set;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.couchbase.core.mapping.CouchbaseDocument;
import org.springframework.util.Assert;
/**
* javax.validation dependant entities validator. When it is registered as Spring component its automatically invoked
@@ -49,10 +51,12 @@ public class ValidatingCouchbaseEventListener extends AbstractCouchbaseEventList
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({"rawtypes", "unchecked"})
public void onBeforeSave(Object source, CouchbaseDocument dbo) {
LOG.debug("Validating object: {}", source);
if (LOG.isDebugEnabled()) {
LOG.debug("Validating object: {}", source);
}
Set violations = validator.validate(source);
if (!violations.isEmpty()) {

View File

@@ -0,0 +1,26 @@
/*
* 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.
*/
/**
* This package contains the specific implementations and core classes for
* Spring Data Couchbase internals. It also contains Couchbase implementation
* to support the Spring Data template abstraction.
* <br/>
* The template provides lower level access to the underlying database and also serves as the foundation for
* repositories. Any time a repository is too high-level for you needs chances are good that the templates will serve
* you well.
*/
package org.springframework.data.couchbase.core;

View File

@@ -1,74 +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.monitor;
import com.couchbase.client.CouchbaseClient;
import org.springframework.web.client.RestTemplate;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Base class to encapsulate common configuration settings.
*
* @author Michael Nitschinger
*/
public abstract class AbstractMonitor {
private CouchbaseClient client;
private RestTemplate template = new RestTemplate();
protected AbstractMonitor(final CouchbaseClient client) {
this.client = client;
}
public CouchbaseClient getClient() {
return client;
}
protected RestTemplate getTemplate() {
return template;
}
protected String randomAvailableHostname() {
List<SocketAddress> available = (ArrayList<SocketAddress>) client.getAvailableServers();
Collections.shuffle(available);
return ((InetSocketAddress) available.get(0)).getHostName();
}
/**
* Fetches stats for all nodes.
*
* @return stats for each node
*/
protected Map<SocketAddress, Map<String, String>> getStats() {
return client.getStats();
}
/**
* Returns stats for an individual node.
*/
protected Map<String, String> getStats(SocketAddress node) {
return getStats().get(node);
}
}

View File

@@ -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,28 +16,35 @@
package org.springframework.data.couchbase.monitor;
import com.couchbase.client.CouchbaseClient;
import java.net.InetAddress;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.bucket.BucketInfo;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import java.net.SocketAddress;
/**
* Exposes basic client information.
*
* @author Michael Nitschinger
* @author Simon Baslé
*/
@ManagedResource(description = "Client Information")
public class ClientInfo extends AbstractMonitor {
@ManagedResource(description = "Client Information")
public class ClientInfo {
public ClientInfo(final CouchbaseClient client) {
super(client);
private final Bucket bucket;
private final BucketInfo info;
public ClientInfo(final Bucket bucket) {
this.bucket = bucket;
this.info = bucket.bucketManager().info();
}
@ManagedAttribute(description = "Hostnames of connected nodes")
public String getHostNames() {
StringBuilder result = new StringBuilder();
for (SocketAddress node : getStats().keySet()) {
for (InetAddress node : info.nodeList()) {
result.append(node.toString()).append(",");
}
return result.toString();
@@ -45,17 +52,9 @@ public class ClientInfo extends AbstractMonitor {
@ManagedAttribute(description = "Number of connected nodes")
public int getNumberOfNodes() {
return getStats().keySet().size();
return info.nodeCount();
}
@ManagedAttribute(description = "Number of connected active nodes")
public int getNumberOfActiveNodes() {
return getClient().getAvailableServers().size();
}
@ManagedAttribute(description = "Number of connected inactive nodes")
public int getNumberOfInactiveNodes() {
return getClient().getUnavailableServers().size();
}
//TODO obtain count of available nodes vs unavailable ones and expose it
}

View File

@@ -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,23 +16,36 @@
package org.springframework.data.couchbase.monitor;
import com.couchbase.client.CouchbaseClient;
import java.net.InetAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.bucket.BucketInfo;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.export.annotation.ManagedResource;
import java.util.HashMap;
import org.springframework.web.client.RestTemplate;
/**
* Exposes basic cluster information.
*
* @author Michael Nitschinger
* @author Simon Baslé
*/
@ManagedResource(description = "Cluster Information")
public class ClusterInfo extends AbstractMonitor {
@ManagedResource(description = "Cluster Information")
public class ClusterInfo {
public ClusterInfo(final CouchbaseClient client) {
super(client);
private final RestTemplate template;
private final Bucket bucket;
private final BucketInfo info;
public ClusterInfo(final Bucket bucket) {
this.template = new RestTemplate();
this.bucket = bucket;
this.info = bucket.bucketManager().info();
}
@ManagedMetric(description = "Total RAM assigned")
@@ -80,27 +93,34 @@ public class ClusterInfo extends AbstractMonitor {
* converted to long.
*
* @param value the value to convert.
*
* @return the converted value.
*/
private long convertPotentialLong(Object value) {
if (value instanceof Integer) {
return new Long((Integer) value);
} else if (value instanceof Long) {
}
else if (value instanceof Long) {
return (Long) value;
} else {
}
else {
throw new IllegalStateException("Cannot convert value to long: " + value);
}
}
protected String randomAvailableHostname() {
List<InetAddress> available = info.nodeList();
Collections.shuffle(available);
return available.get(0).getHostName();
}
private HashMap<String, Object> fetchPoolInfo() {
return getTemplate().getForObject("http://"
+ randomAvailableHostname() + ":8091/pools/default", HashMap.class);
return template.getForObject("http://"
+ randomAvailableHostname() + ":8091/pools/default", HashMap.class);
}
private HashMap<String, HashMap> parseStorageTotals() {
HashMap<String, Object> stats = fetchPoolInfo();
return (HashMap<String, HashMap>) stats.get("storageTotals");
return (HashMap<String, HashMap>) stats.get("storageTotals");
}
}

View File

@@ -0,0 +1,5 @@
/**
* This package contains all classes related to monitoring the Couchbase cluster,
* statistics that will be exposed as JMX beans.
*/
package org.springframework.data.couchbase.monitor;

View File

@@ -0,0 +1,7 @@
/**
* This package contains the Couchbase implementation to support the Spring Data repository abstraction.
* <br/>
* The goal of Spring Data repository abstraction is to significantly reduce the amount of boilerplate code required to
* implement data access layers for various persistence stores.
*/
package org.springframework.data.couchbase.repository;

View File

@@ -16,7 +16,8 @@
package org.springframework.data.couchbase.repository.query;
import com.couchbase.client.protocol.views.Query;
import com.couchbase.client.java.view.ViewQuery;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
@@ -39,21 +40,21 @@ public class ViewBasedCouchbaseQuery implements RepositoryQuery {
@Override
public Object execute(Object[] runtimeParams) {
Query query = null;
ViewQuery query = null;
for (Object param : runtimeParams) {
if (param instanceof Query) {
query = (Query) param;
if (param instanceof ViewQuery) {
query = (ViewQuery) param;
} else {
throw new IllegalStateException("Unknown query param: " + param);
}
}
if (query == null) {
query = new Query();
query = ViewQuery.from(designDocName(), viewName());
}
query.setReduce(false);
query.reduce(false);
return operations.findByView(designDocName(), viewName(), query, method.getEntityInformation().getJavaType());
return operations.findByView(query, method.getEntityInformation().getJavaType());
}
@Override

View File

@@ -16,20 +16,21 @@
package org.springframework.data.couchbase.repository.support;
import com.couchbase.client.protocol.views.ComplexKey;
import com.couchbase.client.protocol.views.Query;
import com.couchbase.client.protocol.views.ViewResponse;
import com.couchbase.client.protocol.views.ViewRow;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.couchbase.client.java.document.json.JsonArray;
import com.couchbase.client.java.view.ViewQuery;
import com.couchbase.client.java.view.ViewResult;
import com.couchbase.client.java.view.ViewRow;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.view.View;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.query.CouchbaseEntityInformation;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Repository base implementation for Couchbase.
*
@@ -130,30 +131,36 @@ public class SimpleCouchbaseRepository<T, ID extends Serializable> implements Co
@Override
public Iterable<T> findAll() {
final ResolvedView resolvedView = determineView();
return couchbaseOperations.findByView(resolvedView.getDesignDocument(), resolvedView.getViewName(), new Query().setReduce(false), entityInformation.getJavaType());
ViewQuery query = ViewQuery.from(resolvedView.getDesignDocument(), resolvedView.getViewName());
query.reduce(false);
return couchbaseOperations.findByView(query, entityInformation.getJavaType());
}
@Override
public Iterable<T> findAll(final Iterable<ID> ids) {
Query query = new Query();
query.setReduce(false);
query.setKeys(ComplexKey.of(ids));
final ResolvedView resolvedView = determineView();
return couchbaseOperations.findByView(resolvedView.getDesignDocument(), resolvedView.getViewName(), query, entityInformation.getJavaType());
ViewQuery query = ViewQuery.from(resolvedView.getDesignDocument(), resolvedView.getViewName());
query.reduce(false);
JsonArray keys = JsonArray.create();
for (ID id : ids) {
keys.add(id);
}
query.keys(keys);
return couchbaseOperations.findByView(query, entityInformation.getJavaType());
}
@Override
public long count() {
Query query = new Query();
query.setReduce(true);
final ResolvedView resolvedView = determineView();
ViewResponse response = couchbaseOperations.queryView(resolvedView.getDesignDocument(), resolvedView.getViewName(), query);
ViewQuery query = ViewQuery.from(resolvedView.getDesignDocument(), resolvedView.getViewName());
query.reduce(true);
ViewResult response = couchbaseOperations.queryView(query);
long count = 0;
for (ViewRow row : response) {
count += Long.parseLong(row.getValue());
count += Long.parseLong(String.valueOf(row.value()));
}
return count;
@@ -161,13 +168,13 @@ public class SimpleCouchbaseRepository<T, ID extends Serializable> implements Co
@Override
public void deleteAll() {
Query query = new Query();
query.setReduce(false);
final ResolvedView resolvedView = determineView();
ViewResponse response = couchbaseOperations.queryView(resolvedView.getDesignDocument(), resolvedView.getViewName(), query);
ViewQuery query = ViewQuery.from(resolvedView.getDesignDocument(), resolvedView.getViewName());
query.reduce(false);
ViewResult response = couchbaseOperations.queryView(query);
for (ViewRow row : response) {
couchbaseOperations.remove(row.getId());
couchbaseOperations.remove(row.id());
}
}

View File

@@ -1,2 +1,4 @@
http\://www.springframework.org/schema/data/couchbase/spring-couchbase-1.0.xsd=org/springframework/data/couchbase/config/spring-couchbase-1.0.xsd
http\://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd=org/springframework/data/couchbase/config/spring-couchbase-1.0.xsd
http\://www.springframework.org/schema/data/couchbase/spring-couchbase-2.0.xsd=org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd
http\://www.springframework.org/schema/data/couchbase/spring-couchbase-env-2.0.xsd=org/springframework/data/couchbase/config/spring-couchbase-env-2.0.xsd
http\://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd=org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd

View File

@@ -1,6 +1,22 @@
Spring Data Couchbase Changelog
===============================
New Major Version: 2.0
----------------------
This version is a complete rewrite of the Spring Data Couchbase project, using the newer 2.x generation
of the Couchbase Java SDK.
Changes in version 2.0.0.M1 (2015-07-03)
----------------------------------------
* DATACOUCH-135 - Migrate to Couchbase SDK 2.2.0-dp, with support for N1QL in template
=================================================================================
| Below are older release notes for the 1st generation of Spring Data Couchbase |
| (based on the 1.x Couchbase Java SDK) |
=================================================================================
Changes in version 1.1.6.RELEASE (2015-07-01)
---------------------------------------------
* DATACOUCH-133 - Fix typos in README.
@@ -224,4 +240,4 @@ Release Notes - Spring Data Couchbase - Version 1.0 M1 - 2013-09-11
* [DATACOUCH-4] - Add Apache 2 license headers
* [DATACOUCH-8] - Overhaul README with uptodate information
* [DATACOUCH-9] - Add View query support to the Template
* [DATACOUCH-10] - Upgrade parent pom to 1.1.0.RELEASE
* [DATACOUCH-10] - Upgrade parent pom to 1.1.0.RELEASE

View File

@@ -1,4 +1,4 @@
Spring Data Couchbase 1.4 M1
Spring Data Couchbase 2.0 BETA
Copyright (c) [2013-2015] Couchbase / Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -6,5 +6,5 @@ You may not use this product except in compliance with the License.
This product may include a number of subcomponents with
separate copyright notices and license terms. Your use of the source
code for the these subcomponents is subject to the terms and
conditions of the subcomponent's license, as noted in the LICENSE file.
code for these subcomponents is subject to the terms and
conditions of the subcomponent's license, as noted in the LICENSE file.

View File

@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.org/schema/data/couchbase"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:repository="http://www.springframework.org/schema/data/repository"
targetNamespace="http://www.springframework.org/schema/data/couchbase"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/context"/>
<xsd:import namespace="http://www.springframework.org/schema/data/repository" schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd"/>
<xsd:include schemaLocation="spring-couchbase-env-2.0.xsd"/>
<xsd:element name="env" type="envType" />
<xsd:element name="cluster">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:sequence>
<xsd:element name="env" type="envType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="node" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="env-ref" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="bucket">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="cluster-ref" type="xsd:string" use="optional"/>
<xsd:attribute name="bucketName" type="xsd:string" use="optional"/>
<xsd:attribute name="bucketPassword" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="template">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The id of the couchbase definition (by default "couchbaseFactory").]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="bucket-ref" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
The reference to a Bucket object.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="com.couchbase.client.java.Bucket"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="converter-ref" type="converterRef" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a CouchbaseConverter instance.
]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.couchbase.core.convert.CouchbaseConverter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="translation-service-ref" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to the Translation Service (by default "translationService").]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.couchbase.core.convert.translation.TranslationService"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="translation-service">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The id of the translation-service definition (by default "translationService").]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="objectMapper" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a configured Jackson ObjectMapper.]]>
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="com.fasterxml.jackson.databind.ObjectMapper"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="jmx">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines a JMX Model MBeans for monitoring a Couchbase cluster'.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="bucket-ref" type="couchbaseBucketRef" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the CouchbaseBucket object that determines what connection to monitor. (by default "couchbaseBucket").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="converterRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.couchbase.core.convert.CouchbaseConverter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="couchbaseTemplateRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.couchbase.core.CouchbaseTemplate"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="couchbaseBucketRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.couchbase.config.CouchbaseBucketFactoryBean"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.org/schema/data/couchbase"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.springframework.org/schema/data/couchbase"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/context"/>
<xsd:simpleType name="retryStrategyType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="BestEffort"/>
<xsd:enumeration value="FailFast"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="envType">
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="retryStrategy" type="retryStrategyType"/>
<xsd:attribute name="managementTimeout" type="xsd:long"/>
<xsd:attribute name="queryTimeout" type="xsd:long"/>
<xsd:attribute name="viewTimeout" type="xsd:long"/>
<xsd:attribute name="kvTimeout" type="xsd:long"/>
<xsd:attribute name="connectTimeout" type="xsd:long"/>
<xsd:attribute name="disconnectTimeout" type="xsd:long"/>
<xsd:attribute name="dnsSrvEnabled" type="xsd:boolean"/>
<xsd:attribute name="dcpEnabled" type="xsd:boolean"/>
<xsd:attribute name="sslEnabled" type="xsd:boolean"/>
<xsd:attribute name="sslKeystoreFile" type="xsd:string"/>
<xsd:attribute name="sslKeystorePassword" type="xsd:string"/>
<xsd:attribute name="queryEnabled" type="xsd:boolean"/>
<xsd:attribute name="queryPort" type="xsd:int"/>
<xsd:attribute name="bootstrapHttpEnabled" type="xsd:boolean"/>
<xsd:attribute name="bootstrapCarrierEnabled" type="xsd:boolean"/>
<xsd:attribute name="bootstrapHttpDirectPort" type="xsd:int"/>
<xsd:attribute name="bootstrapHttpSslPort" type="xsd:int"/>
<xsd:attribute name="bootstrapCarrierDirectPort" type="xsd:int"/>
<xsd:attribute name="bootstrapCarrierSslPort" type="xsd:int"/>
<xsd:attribute name="ioPoolSize" type="xsd:int"/>
<xsd:attribute name="computationPoolSize" type="xsd:int"/>
<xsd:attribute name="responseBufferSize" type="xsd:int"/>
<xsd:attribute name="requestBufferSize" type="xsd:int"/>
<xsd:attribute name="kvEndpoints" type="xsd:int"/>
<xsd:attribute name="viewEndpoints" type="xsd:int"/>
<xsd:attribute name="queryEndpoints" type="xsd:int"/>
<xsd:attribute name="maxRequestLifetime" type="xsd:long"/>
<xsd:attribute name="keepAliveInterval" type="xsd:long"/>
<xsd:attribute name="autoreleaseAfter" type="xsd:long"/>
<xsd:attribute name="bufferPoolingEnabled" type="xsd:boolean"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>

View File

@@ -1,74 +0,0 @@
package org.springframework.data.couchbase;
import com.couchbase.client.ClusterManager;
import com.couchbase.client.clustermanager.BucketType;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.Arrays;
public class BucketCreator implements InitializingBean {
private final Logger logger = LoggerFactory.getLogger(BucketCreator.class);
private final String hostUri;
private final String adminUser;
private final String adminPass;
public BucketCreator(String host, String user, String pass) {
hostUri = host;
adminUser = user;
adminPass = pass;
}
@Override
public void afterPropertiesSet() throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(adminUser, adminPass));
client.setCredentialsProvider(credentialsProvider);
ClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory(client);
RestTemplate template = new RestTemplate(rf);
String fullUri = "http://" + hostUri + ":8091/pools/default/buckets/default";
ResponseEntity<String> entity = null;
try {
entity = template.getForEntity(fullUri, String.class);
} catch (HttpClientErrorException ex) {
logger.info("Got execpetion while looking for bucket: " + ex.getMessage());
if (ex.getMessage().equals("404 Object Not Found")) {
logger.info("Creating default bucket with admin credentials.");
createBucket();
return;
} else {
throw new RuntimeException("Could not see if bucket is already created.", ex);
}
}
logger.info("Checking for bucket returned status code " + entity.getStatusCode());
}
private void createBucket() throws Exception {
ClusterManager bucketManager =
new ClusterManager(Arrays.asList(URI.create("http://" + hostUri + ":8091")), adminUser, adminPass);
bucketManager.createDefaultBucket(BucketType.COUCHBASE, 128, 0, true);
logger.info("Finished creating bucket, sleeping for warmup.");
Thread.sleep(5000);
bucketManager.shutdown();
}
}

Some files were not shown because too many files have changed in this diff Show More