diff --git a/README.md b/README.md index cec96fc7..b068acb1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Spring Data Couchbase - v2 +This branch is a work in progress, it will contain the do-over of the `Spring-Data Couchbase` connector +for the `Couchbase Java SDK 2.x` generation. + +Below is the v1 README as of `75bce39`: + # Spring Data Couchbase The primary goal of the [Spring Data](http://www.springsource.org/spring-data) project is to make it easier to build diff --git a/pom.xml b/pom.xml index 9739b8ed..46ca3124 100644 --- a/pom.xml +++ b/pom.xml @@ -1,155 +1,164 @@ - + - 4.0.0 + 4.0.0 - org.springframework.data - spring-data-couchbase - 1.4.0.BUILD-SNAPSHOT + org.springframework.data + spring-data-couchbase + 2.0.0.BUILD-SNAPSHOT - Spring Data Couchbase - Spring Data integration for Couchbase - https://github.com/SpringSource/spring-data-couchbase + Spring Data Couchbase + Spring Data integration for Couchbase + https://github.com/SpringSource/spring-data-couchbase - - org.springframework.data.build - spring-data-parent - 1.7.0.BUILD-SNAPSHOT - + + org.springframework.data.build + spring-data-parent + 1.7.0.BUILD-SNAPSHOT + - + - DATACOUCH + DATACOUCH - 1.4.7 - 2.3.2 - 1.11.0.BUILD-SNAPSHOT - 1.0.0.GA - + 2.2.0-dp + 2.3.2 + 1.11.0.BUILD-SNAPSHOT + 1.0.0.GA + - + - - org.springframework - spring-context - - - org.springframework - spring-web - - - org.springframework - spring-tx - + + org.springframework + spring-context + + + org.springframework + spring-web + + + org.springframework + spring-tx + - - ${project.groupId} - spring-data-commons - ${springdata.commons} - + + ${project.groupId} + spring-data-commons + ${springdata.commons} + - - com.couchbase.client - couchbase-client - ${couchbase} - + + com.couchbase.client + java-client + ${couchbase} + - - org.springframework - spring-test - ${spring} - test - + + org.springframework + spring-test + ${spring} + test + - - org.hibernate - hibernate-validator - 4.2.0.Final - test - + + org.hibernate + hibernate-validator + 4.2.0.Final + test + - - org.apache.httpcomponents - httpclient - 4.3.3 - test - + + org.apache.httpcomponents + httpclient + 4.3.3 + test + - - com.fasterxml.jackson.core - jackson-databind - ${jackson} - + + com.fasterxml.jackson.core + jackson-databind + ${jackson} + - - joda-time - joda-time - ${jodatime} - true - + + joda-time + joda-time + ${jodatime} + true + - - - javax.validation - validation-api - ${validation} - true - + + + javax.validation + validation-api + ${validation} + true + - - - javax.enterprise - cdi-api - ${cdi} - provided - true - + + + javax.enterprise + cdi-api + ${cdi} + provided + true + - - org.apache.openwebbeans.test - cditest-owb - ${webbeans} - test - + + org.apache.openwebbeans.test + cditest-owb + ${webbeans} + test + - - javax.servlet - servlet-api - 3.0-alpha-1 - test - + + javax.servlet + servlet-api + 3.0-alpha-1 + test + - + - - - spring-libs-snapshot - https://repo.spring.io/libs-snapshot - - + + + spring-libs-snapshot + https://repo.spring.io/libs-snapshot + + + couchbase + couchbase repo + http://files.couchbase.com/maven2 + + false + + + - - - spring-plugins-release - https://repo.spring.io/plugins-release - - + + + spring-plugins-release + https://repo.spring.io/plugins-release + + - - - - org.apache.maven.plugins - maven-assembly-plugin - - - org.codehaus.mojo - wagon-maven-plugin - - - org.asciidoctor - asciidoctor-maven-plugin - - - + + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.codehaus.mojo + wagon-maven-plugin + + + org.asciidoctor + asciidoctor-maven-plugin + + + - + \ No newline at end of file diff --git a/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java new file mode 100644 index 00000000..f9d8e863 --- /dev/null +++ b/src/integration/java/org/springframework/data/couchbase/IntegrationTestApplicationConfig.java @@ -0,0 +1,67 @@ +package org.springframework.data.couchbase; + +import java.util.Collections; +import java.util.List; + +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.data.couchbase.core.WriteResultChecking; + +@Configuration +public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfiguration { + + @Autowired + private Environment springEnv; + + @Bean + public String couchbaseAdminUser() { + return springEnv.getProperty("couchbase.adminUser", "Administrator"); + } + + @Bean + public String couchbaseAdminPassword() { + return springEnv.getProperty("couchbase.adminUser", "password"); + } + + @Override + protected List getBootstrapHosts() { + return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1")); + } + + @Override + protected String getBucketName() { + return springEnv.getProperty("couchbase.bucket", "default"); + } + + @Override + protected String getBucketPassword() { + return springEnv.getProperty("couchbase.password", ""); + } + + + //TODO maybe create the bucket if doesn't exist + + @Override + protected CouchbaseEnvironment getEnvironment() { + return DefaultCouchbaseEnvironment.builder() + .connectTimeout(10000) + .kvTimeout(10000) + .queryTimeout(10000) + .viewTimeout(10000) + .build(); + } + + @Override + public CouchbaseTemplate couchbaseTemplate() throws Exception { + CouchbaseTemplate template = super.couchbaseTemplate(); + template.setWriteResultChecking(WriteResultChecking.LOG); + return template; + } +} diff --git a/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java b/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java new file mode 100644 index 00000000..c235f80a --- /dev/null +++ b/src/integration/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +/** + * @author Michael Nitschinger + */ +public class CouchbaseTemplateParserIntegrationTests { + + DefaultListableBeanFactory factory; + BeanDefinitionReader reader; + + @Before + public void setUp() { + factory = new DefaultListableBeanFactory(); + reader = new XmlBeanDefinitionReader(factory); + } + + @Test + public void readsCouchbaseTemplateAttributesCorrectly() { + reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-bean.xml")); + + BeanDefinition definition = factory.getBeanDefinition("couchbaseTemplate"); + assertEquals(1, definition.getConstructorArgumentValues().getArgumentCount()); + + factory.getBean("couchbaseTemplate"); + } + + @Test + public void readsCouchbaseTemplateWithTranslationServiceAttributesCorrectly() { + reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-template-with-translation-service-bean.xml")); + + BeanDefinition definition = factory.getBeanDefinition("couchbaseTemplate"); + assertEquals(2, definition.getConstructorArgumentValues().getArgumentCount()); + + factory.getBean("couchbaseTemplate"); + } + + /** + * Test case for DATACOUCH-47. + */ + @Test + public void allowsMultipleBuckets() { + reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbase-multi-bucket-bean.xml")); + + factory.getBean("cb-template-first"); + factory.getBean("cb-template-second"); + } + +} diff --git a/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java new file mode 100644 index 00000000..a7db9bf7 --- /dev/null +++ b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java @@ -0,0 +1,643 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.core; + +import static com.couchbase.client.java.query.Select.select; +import static com.couchbase.client.java.query.dsl.Expression.i; +import static com.couchbase.client.java.query.dsl.Expression.s; +import static com.couchbase.client.java.query.dsl.Expression.x; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.document.RawJsonDocument; +import com.couchbase.client.java.error.DocumentDoesNotExistException; +import com.couchbase.client.java.query.Query; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.dsl.Expression; +import com.couchbase.client.java.view.Stale; +import com.couchbase.client.java.view.ViewQuery; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Version; +import org.springframework.data.couchbase.IntegrationTestApplicationConfig; +import org.springframework.data.couchbase.core.mapping.Document; +import org.springframework.data.couchbase.core.mapping.Field; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Michael Nitschinger + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = IntegrationTestApplicationConfig.class) +@TestExecutionListeners(CouchbaseTemplateViewListener.class) +public class CouchbaseTemplateTests { + + @Autowired + private Bucket client; + + @Autowired + private CouchbaseTemplate template; + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private void removeIfExist(String key) { + try { + client.remove(key); + } + catch (DocumentDoesNotExistException e) { + //ignore + } + } + + @Test + public void saveSimpleEntityCorrectly() throws Exception { + String id = "beers:awesome-stout"; + String name = "The Awesome Stout"; + boolean active = false; + Beer beer = new Beer(id).setName(name).setActive(active); + + template.save(beer); + RawJsonDocument resultDoc = client.get(id, RawJsonDocument.class); + assertNotNull(resultDoc); + String result = resultDoc.content(); + assertNotNull(result); + Map resultConv = MAPPER.readValue(result, new TypeReference>() {}); + + 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 resultConv = MAPPER.readValue(result, new TypeReference>() {}); + 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>() {}); + 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 names = new ArrayList(); + names.add("Michael"); + names.add("Thomas"); + names.add(null); + List votes = new LinkedList(); + Map info1 = new HashMap(); + info1.put("foo", true); + info1.put("bar", false); + info1.put("nullValue", null); + Map info2 = new HashMap(); + + 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 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 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 firstnames; + @Field + private final List votes; + + @Field + private final Map info1; + @Field + private final Map info2; + + public ComplexPerson(String id, List firstnames, + List votes, Map info1, + Map info2) { + this.id = id; + this.firstnames = firstnames; + this.votes = votes; + this.info1 = info1; + this.info2 = info2; + } + + List getFirstnames() { + return firstnames; + } + + List getVotes() { + return votes; + } + + Map getInfo1() { + return info1; + } + + Map 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 integerClass; + + private String value; + + SimpleWithClass(final String id, final Class integerClass) { + this.id = id; + this.integerClass = integerClass; + } + + String getId() { + return id; + } + + void setId(final String id) { + this.id = id; + } + + Class getIntegerClass() { + return integerClass; + } + + void setIntegerClass(final Class 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; + } +} diff --git a/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java new file mode 100644 index 00000000..07900d62 --- /dev/null +++ b/src/integration/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java @@ -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); + } + +} diff --git a/src/test/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java b/src/integration/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java similarity index 66% rename from src/test/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java rename to src/integration/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java index a8b9e8a3..62d71e0d 100644 --- a/src/test/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java +++ b/src/integration/java/org/springframework/data/couchbase/monitor/ClientInfoTests.java @@ -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())); + } } diff --git a/src/test/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java b/src/integration/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java similarity index 65% rename from src/test/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java rename to src/integration/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java index dafa7cf1..63c5441c 100644 --- a/src/test/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java +++ b/src/integration/java/org/springframework/data/couchbase/monitor/ClusterInfoTests.java @@ -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)); + } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java b/src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java similarity index 58% rename from src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java rename to src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java index fa5531f1..13420e40 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewListener.java @@ -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 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); } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java b/src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java similarity index 81% rename from src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java rename to src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java index 585b5faa..2bc75eac 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryViewTests.java @@ -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 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)); } diff --git a/src/test/java/org/springframework/data/couchbase/repository/CustomUserRepository.java b/src/integration/java/org/springframework/data/couchbase/repository/CustomUserRepository.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/CustomUserRepository.java rename to src/integration/java/org/springframework/data/couchbase/repository/CustomUserRepository.java diff --git a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java similarity index 64% rename from src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java rename to src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java index b6c28330..b87fd345 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java @@ -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 views = Collections.singletonList(view); + DesignDocument designDoc = DesignDocument.create("user", views); + client.bucketManager().upsertDesignDocument(designDoc); } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java similarity index 82% rename from src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java rename to src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java index 00033329..75676d96 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryTests.java @@ -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 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 users = repository.customViewQuery(new Query().setLimit(2).setStale(Stale.FALSE)); + Iterable users = repository.customViewQuery(ViewQuery.from("", "").limit(2).stale(Stale.FALSE)); int size = 0; for (User u : users) { size++; diff --git a/src/test/java/org/springframework/data/couchbase/repository/User.java b/src/integration/java/org/springframework/data/couchbase/repository/User.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/User.java rename to src/integration/java/org/springframework/data/couchbase/repository/User.java diff --git a/src/test/java/org/springframework/data/couchbase/repository/UserRepository.java b/src/integration/java/org/springframework/data/couchbase/repository/UserRepository.java similarity index 89% rename from src/test/java/org/springframework/data/couchbase/repository/UserRepository.java rename to src/integration/java/org/springframework/data/couchbase/repository/UserRepository.java index d8c04262..866a3ea5 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/UserRepository.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/UserRepository.java @@ -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 { @View(designDocument = "user", viewName = "all") - Iterable customViewQuery(Query query); + Iterable customViewQuery(ViewQuery query); } diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepository.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepository.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepository.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepository.java diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryCustom.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryCustom.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryCustom.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryCustom.java diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryImpl.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryImpl.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryImpl.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiPersonRepositoryImpl.java diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java similarity index 82% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java index 9fab73d0..d6c99c74 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryClient.java @@ -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; } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java similarity index 80% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java index b4c91043..91ab94e6 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CdiRepositoryTests.java @@ -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 views = Collections.singletonList(view); + DesignDocument designDoc = DesignDocument.create("person", views); + client.bucketManager().upsertDesignDocument(designDoc); } /** diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java similarity index 58% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java index 1c1f2c9a..c32da14f 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseClientProducer.java @@ -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(); } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java similarity index 88% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java index bf3f1d84..f95eacab 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java +++ b/src/integration/java/org/springframework/data/couchbase/repository/cdi/CouchbaseOperationsProducer.java @@ -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); diff --git a/src/test/java/org/springframework/data/couchbase/repository/cdi/Person.java b/src/integration/java/org/springframework/data/couchbase/repository/cdi/Person.java similarity index 100% rename from src/test/java/org/springframework/data/couchbase/repository/cdi/Person.java rename to src/integration/java/org/springframework/data/couchbase/repository/cdi/Person.java diff --git a/src/integration/resources/META-INF/beans.xml b/src/integration/resources/META-INF/beans.xml new file mode 100644 index 00000000..71dc6db1 --- /dev/null +++ b/src/integration/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + + diff --git a/src/test/resources/namespace/couchbase-multi-bucket-bean.xml b/src/integration/resources/configurations/couchbase-multi-bucket-bean.xml similarity index 50% rename from src/test/resources/namespace/couchbase-multi-bucket-bean.xml rename to src/integration/resources/configurations/couchbase-multi-bucket-bean.xml index be4d32aa..1a480dd1 100644 --- a/src/test/resources/namespace/couchbase-multi-bucket-bean.xml +++ b/src/integration/resources/configurations/couchbase-multi-bucket-bean.xml @@ -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"> - - + + - - - - - - - - - - + + + + \ No newline at end of file diff --git a/src/test/resources/namespace/couchbase-template-bean.xml b/src/integration/resources/configurations/couchbase-template-bean.xml similarity index 88% rename from src/test/resources/namespace/couchbase-template-bean.xml rename to src/integration/resources/configurations/couchbase-template-bean.xml index 6ccb176b..9b0ada0b 100644 --- a/src/test/resources/namespace/couchbase-template-bean.xml +++ b/src/integration/resources/configurations/couchbase-template-bean.xml @@ -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"> - + + + diff --git a/src/test/resources/namespace/couchbase-template-with-translation-service-bean.xml b/src/integration/resources/configurations/couchbase-template-with-translation-service-bean.xml similarity index 91% rename from src/test/resources/namespace/couchbase-template-with-translation-service-bean.xml rename to src/integration/resources/configurations/couchbase-template-with-translation-service-bean.xml index 77402784..e2f31a1f 100644 --- a/src/test/resources/namespace/couchbase-template-with-translation-service-bean.xml +++ b/src/integration/resources/configurations/couchbase-template-with-translation-service-bean.xml @@ -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"> - + + + diff --git a/src/test/resources/namespace/couchbase.properties b/src/integration/resources/namespace/couchbase.properties similarity index 100% rename from src/test/resources/namespace/couchbase.properties rename to src/integration/resources/namespace/couchbase.properties diff --git a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCache.java b/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCache.java deleted file mode 100644 index 32625792..00000000 --- a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCache.java +++ /dev/null @@ -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 - * Official Spring Cache Reference - * @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 get(final Object key, final Class 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); - } -} diff --git a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheManager.java b/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheManager.java deleted file mode 100644 index 26e5b6cb..00000000 --- a/src/main/java/org/springframework/data/couchbase/cache/CouchbaseCacheManager.java +++ /dev/null @@ -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 clients; - - /** - * Holds the TTL configuration for each cache. - */ - private final HashMap ttlConfiguration; - - /** - * Construct a new CouchbaseCacheManager. - * - * @param clients one ore more CouchbaseClients to reference. - */ - public CouchbaseCacheManager(final HashMap clients) { - this.clients = clients; - this.ttlConfiguration = new HashMap(); - } - - /** - * 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 clients, final HashMap ttlConfiguration) { - this.clients = clients; - this.ttlConfiguration = ttlConfiguration; - } - - /** - * Returns a Map of all CouchbaseClients with name. - * - * @return the actual CouchbaseClient instances. - */ - public final HashMap getClients() { - return clients; - } - - /** - * Populates all caches. - * - * @return a collection of loaded caches. - */ - @Override - protected final Collection loadCaches() { - Collection caches = new LinkedHashSet(); - - for (Map.Entry 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); - } - -} diff --git a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java index 8f3f5ca5..274638f7 100644 --- a/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java +++ b/src/main/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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 bootstrapHosts(); + protected abstract List 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.

* * @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for - * entities. + * entities. */ protected String getMappingBasePackage() { return getClass().getPackage().getName(); @@ -225,19 +239,4 @@ public abstract class AbstractCouchbaseConfiguration { protected FieldNamingStrategy fieldNamingStrategy() { return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() : PropertyNameFieldNamingStrategy.INSTANCE; } - - /** - * Converts the given list of hostnames into parsable URIs. - * - * @param hosts the list of hosts to convert. - * @return the converted URIs. - */ - protected static List bootstrapUris(List hosts) throws URISyntaxException { - List uris = new ArrayList(); - for (String host : hosts) { - uris.add(new URI("http://" + host + ":8091/pools")); - } - return uris; - } - } diff --git a/src/main/java/org/springframework/data/couchbase/config/BeanNames.java b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java index 4e43ec8d..05add28b 100644 --- a/src/main/java/org/springframework/data/couchbase/config/BeanNames.java +++ b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -20,22 +20,32 @@ package org.springframework.data.couchbase.config; * Contains default bean names that will be used when no "id" is supplied to the beans. * * @author Michael Nitschinger + * @author Simon Baslé */ -public class BeanNames { +class BeanNames { /** - * Refers to the "" bean. + * Refers to the "<couchbase:env />" bean. */ - static final String COUCHBASE = "couchbase"; + static final String COUCHBASE_ENV = "couchbaseEnv"; + /** + * Refers to the "<couchbase:cluster />" bean. + */ + static final String COUCHBASE_CLUSTER = "couchbaseCluster"; /** - * Refers to the "" bean. + * Refers to the "<couchbase:bucket />" bean. + */ + static final String COUCHBASE_BUCKET = "couchbaseBucket"; + + /** + * Refers to the "<couchbase:template />" bean. */ static final String COUCHBASE_TEMPLATE = "couchbaseTemplate"; /** - * Refers to the "" bean + * Refers to the "<couchbase:translation-service />" bean */ - static final String TRANSLATION_SERVICE = "translationService"; + static final String TRANSLATION_SERVICE = "couchbaseTranslationService"; } diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java new file mode 100644 index 00000000..a4dd771e --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseBucket; + +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.data.couchbase.core.CouchbaseExceptionTranslator; + +/** + * The Factory Bean to help {@link CouchbaseBucketParser} constructing a {@link Bucket} from a given + * {@link Cluster} reference. + * + * @author Simon Baslé + */ +public class CouchbaseBucketFactoryBean extends AbstractFactoryBean implements PersistenceExceptionTranslator { + + private final Cluster cluster; + private final String bucketName; + private final String bucketPassword; + + private final PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator(); + + public CouchbaseBucketFactoryBean(Cluster cluster) { + this(cluster, null, null); + } + + public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName) { + this(cluster, bucketName, null); + } + + public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName, String bucketPassword) { + this.cluster = cluster; + this.bucketName = bucketName; + this.bucketPassword = bucketPassword; + } + + @Override + public Class getObjectType() { + return CouchbaseBucket.class; + } + + @Override + protected Bucket createInstance() throws Exception { + if (bucketName == null) { + return cluster.openBucket(); + } + else if (bucketPassword == null) { + return cluster.openBucket(bucketName); + } + else { + return cluster.openBucket(bucketName, bucketPassword); + } + } + + @Override + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return exceptionTranslator.translateExceptionIfPossible(ex); + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java new file mode 100644 index 00000000..431b2456 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; + +/** + * The parser for XML definition of a {@link Bucket}, to be constructed from a {@link Cluster} reference. + * If no reference is given, the default reference {@value BeanNames#COUCHBASE_CLUSTER} is used. + * + * See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}. + * + * @author Simon Baslé + */ +public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser { + + /** + * The cluster-ref attribute in a bucket definition defines the cluster to build from. + */ + public static final String CLUSTER_REF_ATTR = "cluster-ref"; + + /** + * The bucketName attribute in a bucket definition defines the name of the bucket to open. + */ + public static final String BUCKETNAME_ATTR = "bucketName"; + + /** + * The bucketPassword attribute in a bucket definition defines the password of the bucket to open. + */ + public static final String BUCKETPASSWORD_ATTR = "bucketPassword"; + + /** + * Resolve the bean ID and assign a default if not set. + * + * @param element the XML element which contains the attributes. + * @param definition the bean definition to work with. + * @param parserContext encapsulates the parsing state and configuration. + * @return the ID to work with. + */ + @Override + protected String resolveId(final Element element, final AbstractBeanDefinition definition, final ParserContext parserContext) { + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_BUCKET; + } + + /** + * Defines the bean class that will be constructed. + * + * @param element the XML element which contains the attributes. + * @return the class type to instantiate. + */ + @Override + protected Class getBeanClass(final Element element) { + return CouchbaseBucketFactoryBean.class; + } + + /** + * Parse the bean definition and build up the bean. + * + * @param element the XML element which contains the attributes. + * @param builder the builder which builds the bean. + */ + @Override + protected void doParse(final Element element, final BeanDefinitionBuilder builder) { + String clusterRef = element.getAttribute(CLUSTER_REF_ATTR); + if (!StringUtils.hasText(clusterRef)) { + clusterRef = BeanNames.COUCHBASE_CLUSTER; + } + builder.addConstructorArgReference(clusterRef); + + String bucketName = element.getAttribute(BUCKETNAME_ATTR); + if (StringUtils.hasText(bucketName)) { + builder.addConstructorArgValue(bucketName); + } + + String bucketPassword = element.getAttribute(BUCKETPASSWORD_ATTR); + if (StringUtils.hasText(bucketPassword)) { + builder.addConstructorArgValue(bucketPassword); + } + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java new file mode 100644 index 00000000..1e78bf08 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseClusterParser.java @@ -0,0 +1,156 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import java.util.ArrayList; +import java.util.List; + +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; + +/** + * The XML parser for a {@link Cluster} definition. + * + * Such a definition can be tuned by either referencing a {@link CouchbaseEnvironment} via + * the {@value #CLUSTER_ENVIRONMENT_REF} attribute or define a custom environment inline via + * the <{@value #CLUSTER_ENVIRONMENT_TAG}> tag (not recommended, environments should be + * shared as possible). If no environment reference or inline description is provided, the + * default environment reference {@value BeanNames#COUCHBASE_ENV} is used. + * + * To bootstrap the connection, one can provide IPs or hostnames of nodes to connect to + * via 1 or more <{@value #CLUSTER_NODE_TAG}> tags. + * + * @author Simon Baslé + */ +public class CouchbaseClusterParser extends AbstractSingleBeanDefinitionParser { + + /** + * The <node> elements in a cluster definition define the bootstrap hosts to use + */ + public static final String CLUSTER_NODE_TAG = "node"; + + /** + * The unique <env> element in a cluster definition define the environment customizations. + * + * @see CouchbaseEnvironmentParser CouchbaseEnvironmentParser for the possible fields. + * @see #CLUSTER_ENVIRONMENT_REF CLUSTER_ENVIRONMENT_REF as an alternative (giving a reference to + * an env instead of inline description, lower precedence) + */ + public static final String CLUSTER_ENVIRONMENT_TAG = "env"; + + /** + * The <env-ref> attribute allows to use a reference to an {@link CouchbaseEnvironment} to + * tune the connection. + * + * @see #CLUSTER_ENVIRONMENT_TAG CLUSTER_ENVIRONMENT_TAG for an inline alternative + * (which takes priority over this reference) + */ + public static final String CLUSTER_ENVIRONMENT_REF = "env-ref"; + + /** + * Resolve the bean ID and assign a default if not set. + * + * @param element the XML element which contains the attributes. + * @param definition the bean definition to work with. + * @param parserContext encapsulates the parsing state and configuration. + * @return the ID to work with. + */ + @Override + protected String resolveId(final Element element, final AbstractBeanDefinition definition, final ParserContext parserContext) { + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_CLUSTER; + } + + /** + * Defines the bean class that will be constructed. + * + * @param element the XML element which contains the attributes. + * @return the class type to instantiate. + */ + @Override + protected Class getBeanClass(final Element element) { + return CouchbaseCluster.class; + } + + /** + * Parse the bean definition and build up the bean. + * + * @param element the XML element which contains the attributes. + * @param bean the builder which builds the bean. + */ + @Override + protected void doParse(final Element element, final BeanDefinitionBuilder bean) { + bean.setFactoryMethod("create"); + bean.setDestroyMethodName("disconnect"); + + parseEnvironment(bean, element); + + List nodes = DomUtils.getChildElementsByTagName(element, CLUSTER_NODE_TAG); + if (nodes != null && nodes.size() > 0) { + List bootstrapUrls = new ArrayList(nodes.size()); + for (int i = 0; i < nodes.size(); i++) { + bootstrapUrls.add(nodes.get(i).getTextContent()); + } + bean.addConstructorArgValue(bootstrapUrls); + } + } + + /** + * @return true if a custom environment was parsed and injected (either reference or inline), false if + * the default environment reference was used. + */ + protected boolean parseEnvironment(BeanDefinitionBuilder clusterBuilder, Element clusterElement) { + //any inline environment description would take precedence over a reference + Element envElement = DomUtils.getChildElementByTagName(clusterElement, CLUSTER_ENVIRONMENT_TAG); + if (envElement != null && envElement.hasAttributes()) { + injectEnvElement(clusterBuilder, envElement); + return true; + } + + //secondly try to see if an env has been referenced + String envRef = clusterElement.getAttribute(CLUSTER_ENVIRONMENT_REF); + if (StringUtils.hasText(envRef)) { + injectEnvReference(clusterBuilder, envRef); + return true; + } + + //if no custom value provided, consider it a reference to the default bean for Couchbase Environment + injectEnvReference(clusterBuilder, BeanNames.COUCHBASE_ENV); + return false; + } + + protected void injectEnvElement(BeanDefinitionBuilder clusterBuilder, Element envElement) { + BeanDefinitionBuilder envDefinitionBuilder = BeanDefinitionBuilder + .genericBeanDefinition(CouchbaseEnvironmentFactoryBean.class); + new CouchbaseEnvironmentParser().doParse(envElement, envDefinitionBuilder); + + clusterBuilder.addConstructorArgValue(envDefinitionBuilder.getBeanDefinition()); + } + + protected void injectEnvReference(BeanDefinitionBuilder clusterBuilder, String envRef) { + clusterBuilder.addConstructorArgReference(envRef); + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java new file mode 100644 index 00000000..e452b50e --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentFactoryBean.java @@ -0,0 +1,259 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import com.couchbase.client.core.retry.BestEffortRetryStrategy; +import com.couchbase.client.core.retry.FailFastRetryStrategy; +import com.couchbase.client.core.retry.RetryStrategy; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; + +import org.springframework.beans.factory.config.AbstractFactoryBean; + +/** + * Factory Bean to help create a CouchbaseEnvironment (by offering setters for supported tuning methods). + * + * @author Simon Baslé + */ +/*package*/ class CouchbaseEnvironmentFactoryBean extends AbstractFactoryBean { + + private static final CouchbaseEnvironment DEFAULT_ENV = DefaultCouchbaseEnvironment.create(); + public static final String RETRYSTRATEGY_FAILFAST = "FailFast"; + public static final String RETRYSTRATEGY_BESTEFFORT = "BestEffort"; + + private long managementTimeout = DEFAULT_ENV.managementTimeout(); + private long queryTimeout = DEFAULT_ENV.queryTimeout(); + private long viewTimeout = DEFAULT_ENV.viewTimeout(); + private long kvTimeout = DEFAULT_ENV.kvTimeout(); + private long connectTimeout = DEFAULT_ENV.connectTimeout(); + private long disconnectTimeout = DEFAULT_ENV.disconnectTimeout(); + private boolean dnsSrvEnabled = DEFAULT_ENV.dnsSrvEnabled(); + + private boolean dcpEnabled = DEFAULT_ENV.dcpEnabled(); + private boolean sslEnabled = DEFAULT_ENV.sslEnabled(); + private String sslKeystoreFile = DEFAULT_ENV.sslKeystoreFile(); + private String sslKeystorePassword = DEFAULT_ENV.sslKeystorePassword(); + private boolean queryEnabled = DEFAULT_ENV.queryEnabled(); + private int queryPort = DEFAULT_ENV.queryPort(); + private boolean bootstrapHttpEnabled = DEFAULT_ENV.bootstrapHttpEnabled(); + private boolean bootstrapCarrierEnabled = DEFAULT_ENV.bootstrapCarrierEnabled(); + private int bootstrapHttpDirectPort = DEFAULT_ENV.bootstrapHttpDirectPort(); + private int bootstrapHttpSslPort = DEFAULT_ENV.bootstrapHttpSslPort(); + private int bootstrapCarrierDirectPort = DEFAULT_ENV.bootstrapCarrierDirectPort(); + private int bootstrapCarrierSslPort = DEFAULT_ENV.bootstrapCarrierSslPort(); + private int ioPoolSize = DEFAULT_ENV.ioPoolSize(); + private int computationPoolSize = DEFAULT_ENV.computationPoolSize(); + private int responseBufferSize = DEFAULT_ENV.responseBufferSize(); + private int requestBufferSize = DEFAULT_ENV.requestBufferSize(); + private int kvEndpoints = DEFAULT_ENV.kvEndpoints(); + private int viewEndpoints = DEFAULT_ENV.viewEndpoints(); + private int queryEndpoints = DEFAULT_ENV.queryEndpoints(); + private RetryStrategy retryStrategy = DEFAULT_ENV.retryStrategy(); + private long maxRequestLifetime = DEFAULT_ENV.maxRequestLifetime(); + private long keepAliveInterval = DEFAULT_ENV.keepAliveInterval(); + private long autoreleaseAfter = DEFAULT_ENV.autoreleaseAfter(); + private boolean bufferPoolingEnabled = DEFAULT_ENV.bufferPoolingEnabled(); + + //These are tunings that are not practical to be exposed in a xml configuration + //or not supposed to be modified that easily: +// observeIntervalDelay +// reconnectDelay +// retryDelay +// userAgent +// packageNameAndVersion +// ioPool +// scheduler +// eventBus + + @Override + public Class getObjectType() { + return DefaultCouchbaseEnvironment.class; + } + + @Override + protected CouchbaseEnvironment createInstance() throws Exception { + return DefaultCouchbaseEnvironment.builder() + .managementTimeout(managementTimeout) + .queryTimeout(queryTimeout) + .viewTimeout(viewTimeout) + .kvTimeout(kvTimeout) + .connectTimeout(connectTimeout) + .disconnectTimeout(disconnectTimeout) + .dnsSrvEnabled(dnsSrvEnabled) + .dcpEnabled(dcpEnabled) + .sslEnabled(sslEnabled) + .sslKeystoreFile(sslKeystoreFile) + .sslKeystorePassword(sslKeystorePassword) + .queryEnabled(queryEnabled) + .queryPort(queryPort) + .bootstrapHttpEnabled(bootstrapHttpEnabled) + .bootstrapCarrierEnabled(bootstrapCarrierEnabled) + .bootstrapHttpDirectPort(bootstrapHttpDirectPort) + .bootstrapHttpSslPort(bootstrapHttpSslPort) + .bootstrapCarrierDirectPort(bootstrapCarrierDirectPort) + .bootstrapCarrierSslPort(bootstrapCarrierSslPort) + .ioPoolSize(ioPoolSize) + .computationPoolSize(computationPoolSize) + .responseBufferSize(responseBufferSize) + .requestBufferSize(requestBufferSize) + .kvEndpoints(kvEndpoints) + .viewEndpoints(viewEndpoints) + .queryEndpoints(queryEndpoints) + .retryStrategy(retryStrategy) + .maxRequestLifetime(maxRequestLifetime) + .keepAliveInterval(keepAliveInterval) + .autoreleaseAfter(autoreleaseAfter) + .bufferPoolingEnabled(bufferPoolingEnabled) + .build(); + } + + /** + * Sets the {@link RetryStrategy} to use from an enum-like String value. + * Either "FailFast" or "BestEffort" are recognized. + * + * @param retryStrategy the string value enum from which to choose a strategy. + */ + public void setRetryStrategy(String retryStrategy) { + if (RETRYSTRATEGY_FAILFAST.equals(retryStrategy)){ + this.retryStrategy = FailFastRetryStrategy.INSTANCE; + } else if (RETRYSTRATEGY_BESTEFFORT.equals(retryStrategy)) { + this.retryStrategy = BestEffortRetryStrategy.INSTANCE; + } + } + + //==== SETTERS for the factory bean ==== + + public void setManagementTimeout(long managementTimeout) { + this.managementTimeout = managementTimeout; + } + + public void setQueryTimeout(long queryTimeout) { + this.queryTimeout = queryTimeout; + } + + public void setViewTimeout(long viewTimeout) { + this.viewTimeout = viewTimeout; + } + + public void setKvTimeout(long kvTimeout) { + this.kvTimeout = kvTimeout; + } + + public void setConnectTimeout(long connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public void setDisconnectTimeout(long disconnectTimeout) { + this.disconnectTimeout = disconnectTimeout; + } + + public void setDnsSrvEnabled(boolean dnsSrvEnabled) { + this.dnsSrvEnabled = dnsSrvEnabled; + } + + public void setDcpEnabled(boolean dcpEnabled) { + this.dcpEnabled = dcpEnabled; + } + + public void setSslEnabled(boolean sslEnabled) { + this.sslEnabled = sslEnabled; + } + + public void setSslKeystoreFile(String sslKeystoreFile) { + this.sslKeystoreFile = sslKeystoreFile; + } + + public void setSslKeystorePassword(String sslKeystorePassword) { + this.sslKeystorePassword = sslKeystorePassword; + } + + public void setQueryEnabled(boolean queryEnabled) { + this.queryEnabled = queryEnabled; + } + + public void setQueryPort(int queryPort) { + this.queryPort = queryPort; + } + + public void setBootstrapHttpEnabled(boolean bootstrapHttpEnabled) { + this.bootstrapHttpEnabled = bootstrapHttpEnabled; + } + + public void setBootstrapCarrierEnabled(boolean bootstrapCarrierEnabled) { + this.bootstrapCarrierEnabled = bootstrapCarrierEnabled; + } + + public void setBootstrapHttpDirectPort(int bootstrapHttpDirectPort) { + this.bootstrapHttpDirectPort = bootstrapHttpDirectPort; + } + + public void setBootstrapHttpSslPort(int bootstrapHttpSslPort) { + this.bootstrapHttpSslPort = bootstrapHttpSslPort; + } + + public void setBootstrapCarrierDirectPort(int bootstrapCarrierDirectPort) { + this.bootstrapCarrierDirectPort = bootstrapCarrierDirectPort; + } + + public void setBootstrapCarrierSslPort(int bootstrapCarrierSslPort) { + this.bootstrapCarrierSslPort = bootstrapCarrierSslPort; + } + + public void setIoPoolSize(int ioPoolSize) { + this.ioPoolSize = ioPoolSize; + } + + public void setComputationPoolSize(int computationPoolSize) { + this.computationPoolSize = computationPoolSize; + } + + public void setResponseBufferSize(int responseBufferSize) { + this.responseBufferSize = responseBufferSize; + } + + public void setRequestBufferSize(int requestBufferSize) { + this.requestBufferSize = requestBufferSize; + } + + public void setKvEndpoints(int kvEndpoints) { + this.kvEndpoints = kvEndpoints; + } + + public void setViewEndpoints(int viewEndpoints) { + this.viewEndpoints = viewEndpoints; + } + + public void setQueryEndpoints(int queryEndpoints) { + this.queryEndpoints = queryEndpoints; + } + + public void setMaxRequestLifetime(long maxRequestLifetime) { + this.maxRequestLifetime = maxRequestLifetime; + } + + public void setKeepAliveInterval(long keepAliveInterval) { + this.keepAliveInterval = keepAliveInterval; + } + + public void setAutoreleaseAfter(long autoreleaseAfter) { + this.autoreleaseAfter = autoreleaseAfter; + } + + public void setBufferPoolingEnabled(boolean bufferPoolingEnabled) { + this.bufferPoolingEnabled = bufferPoolingEnabled; + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java new file mode 100644 index 00000000..6733a942 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentNoShutdownProxy.java @@ -0,0 +1,242 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import com.couchbase.client.core.event.EventBus; +import com.couchbase.client.core.retry.RetryStrategy; +import com.couchbase.client.core.time.Delay; +import com.couchbase.client.deps.io.netty.channel.EventLoopGroup; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import rx.Observable; +import rx.Scheduler; + +/** + * A proxy around a {@link CouchbaseEnvironment} that prevents its {@link #shutdown()} method + * to be invoked. Useful when the delegate is not to be lifecycle-managed by Spring. + * + * @author Simon Baslé + */ +public class CouchbaseEnvironmentNoShutdownProxy implements CouchbaseEnvironment { + + private final CouchbaseEnvironment delegate; + + public CouchbaseEnvironmentNoShutdownProxy(CouchbaseEnvironment delegate) { + this.delegate = delegate; + } + + @Override + public Observable shutdown() { + return Observable.just(false); + } + + //===== DELEGATION METHODS ===== + + @Override + public EventLoopGroup ioPool() { + return delegate.ioPool(); + } + + @Override + public Scheduler scheduler() { + return delegate.scheduler(); + } + + @Override + public boolean dcpEnabled() { + return delegate.dcpEnabled(); + } + + @Override + public boolean sslEnabled() { + return delegate.sslEnabled(); + } + + @Override + public String sslKeystoreFile() { + return delegate.sslKeystoreFile(); + } + + @Override + public String sslKeystorePassword() { + return delegate.sslKeystorePassword(); + } + + @Override + public boolean queryEnabled() { + return delegate.queryEnabled(); + } + + @Override + public int queryPort() { + return delegate.queryPort(); + } + + @Override + public boolean bootstrapHttpEnabled() { + return delegate.bootstrapHttpEnabled(); + } + + @Override + public boolean bootstrapCarrierEnabled() { + return delegate.bootstrapCarrierEnabled(); + } + + @Override + public int bootstrapHttpDirectPort() { + return delegate.bootstrapHttpDirectPort(); + } + + @Override + public int bootstrapHttpSslPort() { + return delegate.bootstrapHttpSslPort(); + } + + @Override + public int bootstrapCarrierDirectPort() { + return delegate.bootstrapCarrierDirectPort(); + } + + @Override + public int bootstrapCarrierSslPort() { + return delegate.bootstrapCarrierSslPort(); + } + + @Override + public int ioPoolSize() { + return delegate.ioPoolSize(); + } + + @Override + public int computationPoolSize() { + return delegate.computationPoolSize(); + } + + @Override + public Delay observeIntervalDelay() { + return delegate.observeIntervalDelay(); + } + + @Override + public Delay reconnectDelay() { + return delegate.reconnectDelay(); + } + + @Override + public Delay retryDelay() { + return delegate.retryDelay(); + } + + @Override + public int requestBufferSize() { + return delegate.requestBufferSize(); + } + + @Override + public int responseBufferSize() { + return delegate.responseBufferSize(); + } + + @Override + public int kvEndpoints() { + return delegate.kvEndpoints(); + } + + @Override + public int viewEndpoints() { + return delegate.viewEndpoints(); + } + + @Override + public int queryEndpoints() { + return delegate.queryEndpoints(); + } + + @Override + public String userAgent() { + return delegate.userAgent(); + } + + @Override + public String packageNameAndVersion() { + return delegate.packageNameAndVersion(); + } + + @Override + public RetryStrategy retryStrategy() { + return delegate.retryStrategy(); + } + + @Override + public long maxRequestLifetime() { + return delegate.maxRequestLifetime(); + } + + @Override + public long autoreleaseAfter() { + return delegate.autoreleaseAfter(); + } + + @Override + public long keepAliveInterval() { + return delegate.keepAliveInterval(); + } + + @Override + public EventBus eventBus() { + return delegate.eventBus(); + } + + @Override + public boolean bufferPoolingEnabled() { + return delegate.bufferPoolingEnabled(); + } + + @Override + public long managementTimeout() { + return delegate.managementTimeout(); + } + + @Override + public long queryTimeout() { + return delegate.queryTimeout(); + } + + @Override + public long viewTimeout() { + return delegate.viewTimeout(); + } + + @Override + public long kvTimeout() { + return delegate.kvTimeout(); + } + + @Override + public long connectTimeout() { + return delegate.connectTimeout(); + } + + @Override + public long disconnectTimeout() { + return delegate.disconnectTimeout(); + } + + @Override + public boolean dnsSrvEnabled() { + return delegate.dnsSrvEnabled(); + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java new file mode 100644 index 00000000..b4bf013f --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParser.java @@ -0,0 +1,141 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.config; + +import static org.springframework.data.config.ParsingUtils.setPropertyValue; + +import com.couchbase.client.core.retry.RetryStrategy; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import org.w3c.dom.Element; + +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; + +/** + * Allows creation of a {@link DefaultCouchbaseEnvironment} via spring XML configuration. + *

+ * The following properties are supported:

    + *
  • {@link DefaultCouchbaseEnvironment.Builder#managementTimeout(long) managementTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#queryTimeout(long) queryTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#viewTimeout(long) viewTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#kvTimeout(long) kvTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#connectTimeout(long) connectTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#disconnectTimeout(long) disconnectTimeout}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#dnsSrvEnabled(boolean) dnsSrvEnabled}
  • + * + *
  • {@link DefaultCouchbaseEnvironment.Builder#dcpEnabled(boolean) dcpEnabled}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#sslEnabled(boolean) sslEnabled}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#sslKeystoreFile(String) sslKeystoreFile}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#sslKeystorePassword(String) sslKeystorePassword}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#queryEnabled(boolean) queryEnabled}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#queryPort(int) queryPort}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpEnabled(boolean) bootstrapHttpEnabled}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierEnabled(boolean) bootstrapCarrierEnabled}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpDirectPort(int) bootstrapHttpDirectPort}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapHttpSslPort(int) bootstrapHttpSslPort}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierDirectPort(int) bootstrapCarrierDirectPort}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bootstrapCarrierSslPort(int) bootstrapCarrierSslPort}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#ioPoolSize(int) ioPoolSize}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#computationPoolSize(int) computationPoolSize}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#responseBufferSize(int) responseBufferSize}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#requestBufferSize(int) requestBufferSize}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#kvEndpoints(int) kvEndpoints}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#viewEndpoints(int) viewEndpoints}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#queryEndpoints(int) queryEndpoints}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#retryStrategy(RetryStrategy) retryStrategy}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#maxRequestLifetime(long) maxRequestLifetime}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#keepAliveInterval(long) keepAliveInterval}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#autoreleaseAfter(long) autoreleaseAfter}
  • + *
  • {@link DefaultCouchbaseEnvironment.Builder#bufferPoolingEnabled(boolean) bufferPoolingEnabled}
  • + *
+ * + * @author Simon Baslé + */ +public class CouchbaseEnvironmentParser extends AbstractSingleBeanDefinitionParser { + + /** + * Resolve the bean ID and assign a default if not set. + * + * @param element the XML element which contains the attributes. + * @param definition the bean definition to work with. + * @param parserContext encapsulates the parsing state and configuration. + * @return the ID to work with. + */ + @Override + protected String resolveId(final Element element, final AbstractBeanDefinition definition, final ParserContext parserContext) { + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_ENV; + } + + /** + * Defines the bean class that will be constructed. + * + * @param element the XML element which contains the attributes. + * @return the class type to instantiate. + */ + @Override + protected Class getBeanClass(final Element element) { + return CouchbaseEnvironmentFactoryBean.class; + } + + /** + * Parse the bean definition and build up the bean. + * + * @param envElement the XML element which contains the attributes. + * @param envDefinitionBuilder the builder which builds the bean. + */ + @Override + protected void doParse(final Element envElement, final BeanDefinitionBuilder envDefinitionBuilder) { + setPropertyValue(envDefinitionBuilder, envElement, "managementTimeout", "managementTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "queryTimeout", "queryTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "viewTimeout", "viewTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "kvTimeout", "kvTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "connectTimeout", "connectTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "disconnectTimeout", "disconnectTimeout"); + setPropertyValue(envDefinitionBuilder, envElement, "dnsSrvEnabled", "dnsSrvEnabled"); + + setPropertyValue(envDefinitionBuilder, envElement, "dcpEnabled", "dcpEnabled"); + setPropertyValue(envDefinitionBuilder, envElement, "sslEnabled", "sslEnabled"); + setPropertyValue(envDefinitionBuilder, envElement, "sslKeystoreFile", "sslKeystoreFile"); + setPropertyValue(envDefinitionBuilder, envElement, "sslKeystorePassword", "sslKeystorePassword"); + setPropertyValue(envDefinitionBuilder, envElement, "queryEnabled", "queryEnabled"); + setPropertyValue(envDefinitionBuilder, envElement, "queryPort", "queryPort"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpEnabled", "bootstrapHttpEnabled"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierEnabled", "bootstrapCarrierEnabled"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpDirectPort", "bootstrapHttpDirectPort"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapHttpSslPort", "bootstrapHttpSslPort"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierDirectPort", "bootstrapCarrierDirectPort"); + setPropertyValue(envDefinitionBuilder, envElement, "bootstrapCarrierSslPort", "bootstrapCarrierSslPort"); + setPropertyValue(envDefinitionBuilder, envElement, "ioPoolSize", "ioPoolSize"); + setPropertyValue(envDefinitionBuilder, envElement, "computationPoolSize", "computationPoolSize"); + setPropertyValue(envDefinitionBuilder, envElement, "responseBufferSize", "responseBufferSize"); + setPropertyValue(envDefinitionBuilder, envElement, "requestBufferSize", "requestBufferSize"); + setPropertyValue(envDefinitionBuilder, envElement, "kvEndpoints", "kvEndpoints"); + setPropertyValue(envDefinitionBuilder, envElement, "viewEndpoints", "viewEndpoints"); + setPropertyValue(envDefinitionBuilder, envElement, "queryEndpoints", "queryEndpoints"); + setPropertyValue(envDefinitionBuilder, envElement, "maxRequestLifetime", "maxRequestLifetime"); + setPropertyValue(envDefinitionBuilder, envElement, "keepAliveInterval", "keepAliveInterval"); + setPropertyValue(envDefinitionBuilder, envElement, "autoreleaseAfter", "autoreleaseAfter"); + setPropertyValue(envDefinitionBuilder, envElement, "bufferPoolingEnabled", "bufferPoolingEnabled"); + + //retry strategy is particular, in the xsd this is an enum (FailFast, BestEffort) + setPropertyValue(envDefinitionBuilder, envElement, "retryStrategy", "retryStrategy"); + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java index fa916cdf..6541b132 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,9 @@ package org.springframework.data.couchbase.config; +import com.couchbase.client.java.Bucket; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; @@ -25,15 +28,15 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.couchbase.monitor.ClientInfo; import org.springframework.data.couchbase.monitor.ClusterInfo; import org.springframework.util.StringUtils; -import org.w3c.dom.Element; /** * Enables Parsing of the "" configuration bean. - * + *

* In order to enable JMX, different JmxComponents need to be registered. The dependency to the original - * {@link com.couchbase.client.CouchbaseClient} object is solved by through the "couchbase-ref" attribute. + * {@link Bucket} object is solved through the "bucket-ref" attribute. * * @author Michael Nitschinger + * @author Simon Baslé */ public class CouchbaseJmxParser implements BeanDefinitionParser { @@ -45,27 +48,28 @@ public class CouchbaseJmxParser implements BeanDefinitionParser { * @return null, because no bean instance needs to be returned. */ public BeanDefinition parse(final Element element, final ParserContext parserContext) { - String name = element.getAttribute("couchbase-ref"); - if (!StringUtils.hasText(name)) { - name = BeanNames.COUCHBASE; + String bucketName = element.getAttribute("bucket-ref"); + if (!StringUtils.hasText(bucketName)) { + bucketName = BeanNames.COUCHBASE_BUCKET; } - registerJmxComponents(name, element, parserContext); + registerJmxComponents(bucketName, element, parserContext); return null; } /** * Register the JMX components in the context. * - * @param refName the reference name to the couchbase client. * @param element the XML element which contains the attributes. * @param parserContext encapsulates the parsing state and configuration. + * @parma refBucketName the reference name to the couchbase bucket. */ - protected void registerJmxComponents(final String refName, final Element element, final ParserContext parserContext) { + protected void registerJmxComponents(final String refBucketName, + final Element element, final ParserContext parserContext) { Object eleSource = parserContext.extractSource(element); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); - createBeanDefEntry(ClientInfo.class, compositeDef, refName, eleSource, parserContext); - createBeanDefEntry(ClusterInfo.class, compositeDef, refName, eleSource, parserContext); + createBeanDefEntry(ClientInfo.class, compositeDef, refBucketName, eleSource, parserContext); + createBeanDefEntry(ClusterInfo.class, compositeDef, refBucketName, eleSource, parserContext); parserContext.registerComponent(compositeDef); } @@ -75,12 +79,12 @@ public class CouchbaseJmxParser implements BeanDefinitionParser { * * @param clazz the class type to register. * @param compositeDef component that can hold nested components. - * @param refName the reference name to the couchbase client. + * @param refName the reference name to the couchbase bucket. * @param eleSource source element to reference. * @param parserContext encapsulates the parsing state and configuration. */ protected void createBeanDefEntry(final Class clazz, final CompositeComponentDefinition compositeDef, - final String refName, final Object eleSource, final ParserContext parserContext) { + final String refName, final Object eleSource, final ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); builder.getRawBeanDefinition().setSource(eleSource); builder.addConstructorArgReference(refName); diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java index 7a1b0f82..bebed47d 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,11 @@ package org.springframework.data.couchbase.config; +import org.springframework.beans.factory.xml.NamespaceHandler; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -import org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension; -import org.springframework.data.repository.config.RepositoryBeanDefinitionParser; -import org.springframework.data.repository.config.RepositoryConfigurationExtension; /** - * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Couchbase configuration. + * {@link NamespaceHandler} for Couchbase configuration. *

* This handler acts as a container for one or more bean parsers and registers them. During parsing, the elements * get analyzed and the appropriate registered parser is called. @@ -35,9 +33,10 @@ public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport { * Register bean definition parsers in the namespace handler. */ public final void init() { - RepositoryConfigurationExtension extension = new CouchbaseRepositoryConfigurationExtension(); - registerBeanDefinitionParser("repositories", new RepositoryBeanDefinitionParser(extension)); - registerBeanDefinitionParser("couchbase", new CouchbaseParser()); + //TODO repositories (CouchbaseRepositoryConfigurationExtension and RepositoryBeanDefinitionParser) + registerBeanDefinitionParser("env", new CouchbaseEnvironmentParser()); + registerBeanDefinitionParser("cluster", new CouchbaseClusterParser()); + registerBeanDefinitionParser("bucket", new CouchbaseBucketParser()); registerBeanDefinitionParser("jmx", new CouchbaseJmxParser()); registerBeanDefinitionParser("template", new CouchbaseTemplateParser()); registerBeanDefinitionParser("translation-service", new CouchbaseTranslationServiceParser()); diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java deleted file mode 100644 index 52b01da5..00000000 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.couchbase.config; - -import com.couchbase.client.CouchbaseClient; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.config.ParsingUtils; -import org.springframework.data.couchbase.core.CouchbaseFactoryBean; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -import java.util.Properties; - -/** - * Parser for "" bean definitions. - *

- * The outcome of this bean definition parser will be a constructed {@link CouchbaseClient}. - * - * @author Michael Nitschinger - */ -public class CouchbaseParser extends AbstractSingleBeanDefinitionParser { - - /** - * Defines the bean class that will be constructed. - * - * @param element the XML element which contains the attributes. - * - * @return the class type to instantiate. - */ - @Override - protected Class getBeanClass(final Element element) { - return CouchbaseFactoryBean.class; - } - - /** - * Parse the bean definition and build up the bean. - * - * @param element the XML element which contains the attributes. - * @param bean the builder which builds the bean. - */ - @Override - protected void doParse(final Element element, final BeanDefinitionBuilder bean) { - ParsingUtils.setPropertyValue(bean, element, "host", "host"); - ParsingUtils.setPropertyValue(bean, element, "bucket", "bucket"); - ParsingUtils.setPropertyValue(bean, element, "password", "password"); - - setLogger(); - } - - private void setLogger() { - Properties systemProperties = System.getProperties(); - systemProperties.put("net.spy.log.LoggerImpl", CouchbaseFactoryBean.DEFAULT_LOGGER_PROPERTY); - System.setProperties(systemProperties); - } - - /** - * Resolve the bean ID and assign a default if not set. - * - * @param element the XML element which contains the attributes. - * @param definition the bean definition to work with. - * @param parserContext encapsulates the parsing state and configuration. - * - * @return the ID to work with. - */ - @Override - protected String resolveId(final Element element, final AbstractBeanDefinition definition, - final ParserContext parserContext) { - String id = super.resolveId(element, definition, parserContext); - return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE; - } - -} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java index 66a2b0d8..59a63b5c 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,14 @@ package org.springframework.data.couchbase.config; +import org.w3c.dom.Element; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.util.StringUtils; -import org.w3c.dom.Element; /** * Parser for "" bean definitions. @@ -39,7 +40,6 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser * @param element the XML element which contains the attributes. * @param definition the bean definition to work with. * @param parserContext encapsulates the parsing state and configuration. - * * @return the ID to work with. */ @Override @@ -52,7 +52,6 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser * Defines the bean class that will be constructed. * * @param element the XML element which contains the attributes. - * * @return the class type to instantiate. */ @Override @@ -68,11 +67,11 @@ public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser */ @Override protected void doParse(final Element element, final BeanDefinitionBuilder bean) { - String clientRef = element.getAttribute("client-ref"); + String bucketRef = element.getAttribute("bucket-ref"); String converterRef = element.getAttribute("converter-ref"); String translationServiceRef = element.getAttribute("translation-service-ref"); - bean.addConstructorArgReference(StringUtils.hasText(clientRef) ? clientRef : BeanNames.COUCHBASE); + bean.addConstructorArgReference(StringUtils.hasText(bucketRef) ? bucketRef : BeanNames.COUCHBASE_BUCKET); if (StringUtils.hasText(converterRef)) { bean.addConstructorArgReference(converterRef); diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java index eb4920cc..89f2e52a 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTranslationServiceParser.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,13 +17,14 @@ package org.springframework.data.couchbase.config; import com.fasterxml.jackson.databind.ObjectMapper; +import org.w3c.dom.Element; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService; import org.springframework.util.StringUtils; -import org.w3c.dom.Element; /** * Enables Parsing of the "" configuration bean. @@ -36,7 +37,6 @@ public class CouchbaseTranslationServiceParser extends AbstractSingleBeanDefinit * Defines the bean class that will be constructed. * * @param element the XML element which contains the attributes. - * * @return the class type to instantiate. */ @Override @@ -55,17 +55,18 @@ public class CouchbaseTranslationServiceParser extends AbstractSingleBeanDefinit final String objectMapper = element.getAttribute("objectMapper"); if (StringUtils.hasText(objectMapper)) { bean.addPropertyReference("objectMapper", objectMapper); - } else { + } + else { bean.addPropertyValue("objectMapper", new ObjectMapper()); } } + /** * Resolve the bean ID and assign a default if not set. * * @param element the XML element which contains the attributes. * @param definition the bean definition to work with. * @param parserContext encapsulates the parsing state and configuration. - * * @return the ID to work with (e.g., "translationService") */ @Override diff --git a/src/main/java/org/springframework/data/couchbase/config/package-info.java b/src/main/java/org/springframework/data/couchbase/config/package-info.java new file mode 100644 index 00000000..4bfb6547 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/package-info.java @@ -0,0 +1,5 @@ +/** + * This package contains all classes needed for specific configuration of + * Spring Data Couchbase. + */ +package org.springframework.data.couchbase.config; \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java b/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java index dfdcd8a3..8e7d90ef 100644 --- a/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java +++ b/src/main/java/org/springframework/data/couchbase/core/BucketCallback.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -30,8 +30,8 @@ public interface BucketCallback { * The enclosed body will be executed on the connected bucket. * * @return the result of the enclosed execution. - * @throws TimeoutException if the enclosed operation timed out. - * @throws ExecutionException if the result could not be retrieved because of a thrown exception before. + * @throws TimeoutException if the enclosed operation timed out. + * @throws ExecutionException if the result could not be retrieved because of a thrown exception before. * @throws InterruptedException if the enclosed operation was interrupted. */ T doInBucket() throws TimeoutException, ExecutionException, InterruptedException; diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java index 16e24f16..d4aed17c 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseDataIntegrityViolationException.java @@ -1,11 +1,11 @@ /* - * Copyright 2013, 2014 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java index fd03b81e..369d4c4f 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseExceptionTranslator.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,19 +16,41 @@ package org.springframework.data.couchbase.core; -import com.couchbase.client.ObservedException; -import com.couchbase.client.ObservedModifiedException; -import com.couchbase.client.ObservedTimeoutException; -import com.couchbase.client.protocol.views.InvalidViewException; -import com.couchbase.client.vbucket.ConnectionException; +import java.util.concurrent.TimeoutException; + +import com.couchbase.client.core.BackpressureException; +import com.couchbase.client.core.BucketClosedException; +import com.couchbase.client.core.DocumentConcurrentlyModifiedException; +import com.couchbase.client.core.ReplicaNotConfiguredException; +import com.couchbase.client.core.RequestCancelledException; +import com.couchbase.client.core.ServiceNotAvailableException; +import com.couchbase.client.core.config.ConfigurationException; +import com.couchbase.client.core.endpoint.SSLException; +import com.couchbase.client.core.endpoint.kv.AuthenticationException; +import com.couchbase.client.core.env.EnvironmentException; +import com.couchbase.client.core.state.NotConnectedException; +import com.couchbase.client.java.error.BucketDoesNotExistException; +import com.couchbase.client.java.error.CASMismatchException; +import com.couchbase.client.java.error.DesignDocumentException; +import com.couchbase.client.java.error.DocumentAlreadyExistsException; +import com.couchbase.client.java.error.DurabilityException; +import com.couchbase.client.java.error.InvalidPasswordException; +import com.couchbase.client.java.error.RequestTooBigException; +import com.couchbase.client.java.error.TemporaryFailureException; +import com.couchbase.client.java.error.TemporaryLockFailureException; +import com.couchbase.client.java.error.TranscodingException; +import com.couchbase.client.java.error.ViewDoesNotExistException; + import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DataRetrievalFailureException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.dao.QueryTimeoutException; +import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.dao.support.PersistenceExceptionTranslator; -import java.util.concurrent.CancellationException; - /** * Simple {@link PersistenceExceptionTranslator} for Couchbase. @@ -38,6 +60,7 @@ import java.util.concurrent.CancellationException; * should not be translated. * * @author Michael Nitschinger + * @author Simon Baslé */ public class CouchbaseExceptionTranslator implements PersistenceExceptionTranslator { @@ -45,28 +68,59 @@ public class CouchbaseExceptionTranslator implements PersistenceExceptionTransla * Translate Couchbase specific exceptions to spring exceptions if possible. * * @param ex the exception to translate. - * * @return the translated exception or null. */ @Override public final DataAccessException translateExceptionIfPossible(final RuntimeException ex) { - if (ex instanceof ConnectionException) { + if (ex instanceof InvalidPasswordException + || ex instanceof NotConnectedException + || ex instanceof ConfigurationException + || ex instanceof EnvironmentException + || ex instanceof InvalidPasswordException + || ex instanceof SSLException + || ex instanceof ServiceNotAvailableException + || ex instanceof BucketClosedException + || ex instanceof BucketDoesNotExistException + || ex instanceof AuthenticationException) { return new DataAccessResourceFailureException(ex.getMessage(), ex); } - if (ex instanceof ObservedException - || ex instanceof ObservedTimeoutException - || ex instanceof ObservedModifiedException) { + if (ex instanceof DocumentAlreadyExistsException) { + return new DuplicateKeyException(ex.getMessage(), ex); + } + + if (ex instanceof CASMismatchException + || ex instanceof DocumentConcurrentlyModifiedException + || ex instanceof ReplicaNotConfiguredException + || ex instanceof DurabilityException) { return new DataIntegrityViolationException(ex.getMessage(), ex); } - if (ex instanceof CancellationException) { - throw new OperationCancellationException(ex.getMessage(), ex); + if (ex instanceof RequestCancelledException + || ex instanceof BackpressureException) { + return new OperationCancellationException(ex.getMessage(), ex); } - if (ex instanceof InvalidViewException) { - throw new InvalidDataAccessResourceUsageException(ex.getMessage(), ex); + if (ex instanceof ViewDoesNotExistException + || ex instanceof RequestTooBigException + || ex instanceof DesignDocumentException) { + return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex); + } + + if (ex instanceof TemporaryLockFailureException + || ex instanceof TemporaryFailureException) { + return new TransientDataAccessResourceException(ex.getMessage(), ex); + } + + if ((ex instanceof RuntimeException && ex.getCause() instanceof TimeoutException)) { + return new QueryTimeoutException(ex.getMessage(), ex); + } + + if (ex instanceof TranscodingException) { + //note: the more specific CouchbaseQueryExecutionException should be thrown by the template + //when dealing with TranscodingException in the query/n1ql methods. + return new DataRetrievalFailureException(ex.getMessage(), ex); } // Unable to translate exception, therefore just throw the original! diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java deleted file mode 100644 index 8918efb9..00000000 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.couchbase.core; - -import com.couchbase.client.CouchbaseClient; -import com.couchbase.client.CouchbaseConnectionFactory; -import com.couchbase.client.CouchbaseConnectionFactoryBuilder; -import net.spy.memcached.FailureMode; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.support.PersistenceExceptionTranslator; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Convenient Factory for configuring a {@link CouchbaseClient}. - * - * To set the properties correctly on the {@link CouchbaseClient} a {@link CouchbaseConnectionFactoryBuilder} is used. - * After all properties are set, the client is constructed and used. - * - * @author Michael Nitschinger - */ -public class CouchbaseFactoryBean implements FactoryBean, InitializingBean, - DisposableBean, PersistenceExceptionTranslator { - - /** - * Defines the default hostname to be used if no other list is supplied. - */ - public static final String DEFAULT_NODE = "127.0.0.1"; - - /** - * Defines the default bucket name to be used if no other bucket name is supplied. - */ - public static final String DEFAULT_BUCKET = "default"; - - /** - * Defines the password of the default bucket. - */ - public static final String DEFAULT_PASSWORD = ""; - - /** - * The name of the default shutdown method to call when the context is destroyed. - */ - public static final String DEFAULT_DESTROY_METHOD = "shutdown"; - - /** - * Use SLF4J as the default logger if not instructed otherwise. - */ - public static final String DEFAULT_LOGGER_PROPERTY = "net.spy.memcached.compat.log.SLF4JLogger"; - - /** - * Holds the enclosed {@link CouchbaseClient}. - */ - private CouchbaseClient couchbaseClient; - - /** - * The exception translator is used to properly map exceptions to spring-type exceptions. - */ - private PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator(); - - /** - * Contains the actual bucket name. - */ - private String bucket; - - /** - * Contains the actual bucket password. - */ - private String password; - - /** - * Contains the list of nodes to connect to. - */ - private List nodes; - - /** - * The builder which allows to customize client settings. - */ - private final CouchbaseConnectionFactoryBuilder builder = new CouchbaseConnectionFactoryBuilder(); - - /** - * Set the observe poll interval in miliseconds. - * - * @param interval the observe poll interval. - */ - public void setObservePollInterval(final int interval) { - builder.setObsPollInterval(interval); - } - - /** - * Set the maximum number of polls. - * - * @param max the maximum number of polls. - */ - public void setObservePollMax(final int max) { - builder.setObsPollMax(max); - } - - /** - * Set the reconnect threshold time in seconds. - * - * @param time the reconnect threshold time. - */ - public void setReconnectThresholdTime(final int time) { - builder.setReconnectThresholdTime(time, TimeUnit.SECONDS); - } - - /** - * Set the view timeout in miliseconds. - * - * @param timeout the view timeout. - */ - public void setViewTimeout(final int timeout) { - builder.setViewTimeout(timeout); - } - - /** - * Set the failure mode if memcached buckets are used. - * - * See the proper values of {@link FailureMode} to use. - * - * @param mode the failure mode. - */ - public void setFailureMode(final String mode) { - builder.setFailureMode(FailureMode.valueOf(mode)); - } - - /** - * Set the operation timeout in miliseconds. - * - * @param timeout the operation timeout. - */ - public void setOpTimeout(final int timeout) { - builder.setOpTimeout(timeout); - } - - /** - * Set the operation queue maximum block time in miliseconds. - * - * @param time the operation queue maximum block time. - */ - public void setOpQueueMaxBlockTime(final int time) { - builder.setOpQueueMaxBlockTime(time); - } - - /** - * Shutdown the client when the bean is destroyed. - * - * @throws Exception if shutdown failed. - */ - @Override - public void destroy() throws Exception { - couchbaseClient.shutdown(); - } - - /** - * Return the underlying {@link CouchbaseClient}. - * - * @return the client object. - * @throws Exception if returning the client failed. - */ - @Override - public CouchbaseClient getObject() throws Exception { - return couchbaseClient; - } - - /** - * Returns the object type of the client. - * - * @return the {@link CouchbaseClient} class. - */ - @Override - public Class getObjectType() { - return CouchbaseClient.class; - } - - /** - * The client should be returned as a singleton. - * - * @return returns true. - */ - @Override - public boolean isSingleton() { - return true; - } - - /** - * Set the bucket to be used. - * - * @param bucket the bucket to use. - */ - public void setBucket(final String bucket) { - this.bucket = bucket; - } - - /** - * Set the password. - * - * @param password the password to use. - */ - public void setPassword(final String password) { - this.password = password; - } - - /** - * Set the array of nodes from a delimited list of hosts. - * - * @param hosts a comma separated list of hosts. - */ - public void setHost(final String hosts) { - this.nodes = convertHosts(hosts); - } - - /** - * Convert a list of hosts into a URI format that can be used by the {@link CouchbaseClient}. - * - * To make it simple to use, the list of hosts can be passed in as a comma separated list. This list gets parsed - * and converted into a URI format that is suitable for the underlying {@link CouchbaseClient} object. - * - * @param hosts the host list to convert. - * @return the converted list with URIs. - */ - private List convertHosts(final String hosts) { - String[] split = hosts.split(","); - List nodes = new ArrayList(); - - try { - for (int i = 0; i < split.length; i++) { - nodes.add(new URI("http://" + split[i] + ":8091/pools")); - } - } catch (URISyntaxException ex) { - throw new BeanCreationException("Could not convert host list." + ex); - } - - return nodes; - } - - /** - * Set the nodes as an array of URIs. - * - * @param nodes the nodes to connect to. - */ - public void setNodes(final URI[] nodes) { - this.nodes = filterNonNullElementsAsList(nodes); - } - - /** - * Convert the array of elements to a list and filter empty or null elements. - * - * @param elements the elements to convert. - * @param the type of the elements. - * @return the converted list. - */ - private List filterNonNullElementsAsList(T[] elements) { - if (elements == null) { - return Collections.emptyList(); - } - - List candidateElements = new ArrayList(); - for (T element : elements) { - if (element != null) { - candidateElements.add(element); - } - } - - return Collections.unmodifiableList(candidateElements); - } - - /** - * Instantiate the {@link CouchbaseClient}. - * - * @throws Exception if something goes wrong during instantiation. - */ - @Override - public void afterPropertiesSet() throws Exception { - nodes = nodes != null ? nodes : Arrays.asList(new URI("http://" + DEFAULT_NODE + ":8091/pools")); - bucket = bucket != null ? bucket : DEFAULT_BUCKET; - password = password != null ? password : DEFAULT_PASSWORD; - - CouchbaseConnectionFactory factory = builder.buildCouchbaseConnection(nodes, bucket, password); - couchbaseClient = new CouchbaseClient(factory); - } - - /** - * Translate exception if possible. - * - * @param ex the exception to translate. - * @return the translate exception. - */ - @Override - public DataAccessException translateExceptionIfPossible(final RuntimeException ex) { - return exceptionTranslator.translateExceptionIfPossible(ex); - } - -} diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java index a50d8c98..0610c9e0 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,20 +17,26 @@ package org.springframework.data.couchbase.core; -import com.couchbase.client.CouchbaseClient; -import com.couchbase.client.protocol.views.Query; -import com.couchbase.client.protocol.views.ViewResponse; -import net.spy.memcached.PersistTo; -import net.spy.memcached.ReplicateTo; -import org.springframework.data.couchbase.core.convert.CouchbaseConverter; - import java.util.Collection; import java.util.List; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.PersistTo; +import com.couchbase.client.java.ReplicateTo; +import com.couchbase.client.java.query.Query; +import com.couchbase.client.java.query.QueryParams; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.Statement; +import com.couchbase.client.java.view.ViewQuery; +import com.couchbase.client.java.view.ViewResult; + +import org.springframework.data.couchbase.core.convert.CouchbaseConverter; + /** * Defines common operations on the Couchbase data source, most commonly implemented by {@link CouchbaseTemplate}. * * @author Michael Nitschinger + * @author Simon Baslé */ public interface CouchbaseOperations { @@ -169,50 +175,71 @@ public interface CouchbaseOperations { * * @param id the unique ID of the document. * @param entityClass the entity to map to. - * * @return returns the found object or null otherwise. */ T findById(String id, Class entityClass); + //TODO add javadoc link to setIncludeDocs when GA + /** * Query a View for a list of documents of type T. *

- *

There is no need to {@link Query#setIncludeDocs(boolean)} explicitely, because it will be set to true all the - * time. It is valid to pass in a empty constructed {@link Query} object.

+ *

There is no need to setIncludeDocs(boolean) explicitly, because it will be set to true all the + * time. It is valid to pass in a empty constructed {@link ViewQuery} object.

*

*

This method does not work with reduced views, because they by design do not contain references to original * objects. Use the provided {@link #queryView} method for more flexibility and direct access.

* - * @param design the name of the design document. - * @param view the name of the viewName. - * @param query the Query object to customize the viewName query. + * @param query the Query object (also specifying view design document and view name). * @param entityClass the entity to map to. - * * @return the converted collection */ - List findByView(String design, String view, Query query, Class entityClass); + List findByView(ViewQuery query, Class entityClass); /** - * Query a View with direct access to the {@link ViewResponse}. + * Query a View with direct access to the {@link ViewResult}. *

This method is available to ease the working with views by still wrapping exceptions into the Spring * infrastructure.

*

It is especially needed if you want to run reduced viewName queries, because they can't be mapped onto entities * directly.

* - * @param design the name of the designDocument document. - * @param view the name of the viewName. - * @param query the Query object to customize the viewName query. - * - * @return ViewResponse containing the results of the query. + * @param query the Query object (also specifying view design document and view name). + * @return ViewResult containing the results of the query. */ - ViewResponse queryView(String design, String view, Query query); + ViewResult queryView(ViewQuery query); + + /** + * Query the N1QL Service for JSON data of type T. This is done via a {@link Query} that can + * contain a {@link Statement}, additional query parameters ({@link QueryParams}) + * and placeholder values if the statement contains placeholders. + *

Use {@link Query}'s factory methods to construct this.

+ * + * @param n1ql the N1QL query. + * @param entityClass the target class for the returned entities. + * @param the entity class + * @return the list of entities matching this query. + */ + List findByN1QL(Query n1ql, Class entityClass); + + /** + * Query the N1QL Service with direct access to the {@link QueryResult}. + *

+ * This is done via a {@link Query} that can + * contain a {@link Statement}, additional query parameters ({@link QueryParams}) + * and placeholder values if the statement contains placeholders.

+ *

+ * Use {@link Query}'s factory methods to construct this.

+ * + * @param n1ql the N1QL query. + * @return {@link QueryResult} containing the results of the n1ql query. + */ + QueryResult queryN1QL(Query n1ql); /** * Checks if the given document exists. * * @param id the unique ID of the document. - * * @return whether the document could be found or not. */ boolean exists(String id); @@ -262,11 +289,17 @@ public interface CouchbaseOperations { * * @param action the action to execute in the callback. * @param the return type. - * * @return the return type. */ T execute(BucketCallback action); + /** + * Returns the linked {@link Bucket} to this template. + * + * @return the client used for the template. + */ + Bucket getCouchbaseBucket(); + /** * Returns the underlying {@link CouchbaseConverter}. * @@ -274,11 +307,4 @@ public interface CouchbaseOperations { */ CouchbaseConverter getConverter(); - /** - * Returns the linked {@link CouchbaseClient} to this template. - * - * @return the client used for the template. - */ - CouchbaseClient getCouchbaseClient(); - } diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java new file mode 100644 index 00000000..7cb25a90 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseQueryExecutionException.java @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2015 the original author or authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.couchbase.core; + +import org.springframework.dao.DataRetrievalFailureException; + +/** + * An {@link DataRetrievalFailureException} that denotes an error during a query (N1QL). + */ +public class CouchbaseQueryExecutionException extends DataRetrievalFailureException { + + public CouchbaseQueryExecutionException(String msg) { + super(msg); + } + + public CouchbaseQueryExecutionException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java index b91594d3..7f707c05 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,22 +16,38 @@ package org.springframework.data.couchbase.core; -import com.couchbase.client.CouchbaseClient; -import com.couchbase.client.protocol.views.Query; -import com.couchbase.client.protocol.views.View; -import com.couchbase.client.protocol.views.ViewResponse; -import com.couchbase.client.protocol.views.ViewRow; -import net.spy.memcached.CASResponse; -import net.spy.memcached.CASValue; -import net.spy.memcached.PersistTo; -import net.spy.memcached.ReplicateTo; -import net.spy.memcached.internal.OperationFuture; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.PersistTo; +import com.couchbase.client.java.ReplicateTo; +import com.couchbase.client.java.document.Document; +import com.couchbase.client.java.document.RawJsonDocument; +import com.couchbase.client.java.document.json.JsonObject; +import com.couchbase.client.java.error.CASMismatchException; +import com.couchbase.client.java.error.TranscodingException; +import com.couchbase.client.java.query.Query; +import com.couchbase.client.java.query.QueryResult; +import com.couchbase.client.java.query.QueryRow; +import com.couchbase.client.java.view.ViewQuery; +import com.couchbase.client.java.view.ViewResult; +import com.couchbase.client.java.view.ViewRow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.dao.QueryTimeoutException; +import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.couchbase.core.convert.CouchbaseConverter; import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService; @@ -50,34 +66,16 @@ import org.springframework.data.couchbase.core.mapping.event.CouchbaseMappingEve import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.BeanWrapper; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - /** * @author Michael Nitschinger * @author Oliver Gierke + * @author Simon Baslé */ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventPublisherAware { private static final Logger LOGGER = LoggerFactory.getLogger(CouchbaseTemplate.class); - private static final Collection ITERABLE_CLASSES; private static final WriteResultChecking DEFAULT_WRITE_RESULT_CHECKING = WriteResultChecking.NONE; - - private final CouchbaseClient client; - protected final MappingContext, CouchbasePersistentProperty> mappingContext; - private final CouchbaseExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator(); - private final TranslationService translationService; - private ApplicationEventPublisher eventPublisher; - - private CouchbaseConverter couchbaseConverter; - private WriteResultChecking writeResultChecking = DEFAULT_WRITE_RESULT_CHECKING; + private static final Collection ITERABLE_CLASSES; static { final Set iterableClasses = new HashSet(); @@ -87,181 +85,66 @@ public class CouchbaseTemplate implements CouchbaseOperations, ApplicationEventP ITERABLE_CLASSES = Collections.unmodifiableCollection(iterableClasses); } - public void setWriteResultChecking(final WriteResultChecking resultChecking) { - writeResultChecking = resultChecking == null ? DEFAULT_WRITE_RESULT_CHECKING : resultChecking; - } + private final Bucket client; + private final CouchbaseConverter converter; + private final TranslationService translationService; - public CouchbaseTemplate(final CouchbaseClient client) { + + private ApplicationEventPublisher eventPublisher; + private WriteResultChecking writeResultChecking = DEFAULT_WRITE_RESULT_CHECKING; + private PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator(); + + protected final MappingContext, CouchbasePersistentProperty> mappingContext; + + public CouchbaseTemplate(final Bucket client) { this(client, null, null); } - public CouchbaseTemplate(final CouchbaseClient client, final TranslationService translationService) { + public CouchbaseTemplate(final Bucket client, final TranslationService translationService) { this(client, null, translationService); } - public CouchbaseTemplate(final CouchbaseClient client, final CouchbaseConverter couchbaseConverter, final TranslationService translationService) { + public CouchbaseTemplate(final Bucket client, final CouchbaseConverter converter, + final TranslationService translationService) { this.client = client; - this.couchbaseConverter = couchbaseConverter == null ? getDefaultConverter() : couchbaseConverter; + this.converter = converter == null ? getDefaultConverter() : converter; this.translationService = translationService == null ? getDefaultTranslationService() : translationService; - mappingContext = this.couchbaseConverter.getMappingContext(); + this.mappingContext = this.converter.getMappingContext(); } - @Override - public void setApplicationEventPublisher(final ApplicationEventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; + private TranslationService getDefaultTranslationService() { + JacksonTranslationService t = new JacksonTranslationService(); + t.afterPropertiesSet(); + return t; } - private static CouchbaseConverter getDefaultConverter() { - final MappingCouchbaseConverter converter = new MappingCouchbaseConverter(new CouchbaseMappingContext()); - converter.afterPropertiesSet(); - return converter; + private CouchbaseConverter getDefaultConverter() { + MappingCouchbaseConverter c = new MappingCouchbaseConverter(new CouchbaseMappingContext()); + c.afterPropertiesSet(); + return c; } - private static TranslationService getDefaultTranslationService() { - final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService(); - jacksonTranslationService.afterPropertiesSet(); - return jacksonTranslationService; - } - - private Object translateEncode(final CouchbaseStorable source) { - return translationService.encode(source); - } - - - private CouchbaseStorable translateDecode(final String source, final CouchbaseStorable target) { - return translationService.decode(source, target); - } - - @Override - public final void insert(final Object objectToInsert) { - insert(objectToInsert, PersistTo.ZERO, ReplicateTo.ZERO); - } - - @Override - public final void insert(final Collection batchToInsert) { - for (final Object toInsert : batchToInsert) { - insert(toInsert); + /** + * Encode a {@link CouchbaseDocument} into a storable representation (JSON) then prepare + * it for storage as a {@link Document}. + */ + private Document encodeAndWrap(final CouchbaseDocument source, Long version) { + String encodedContent = translationService.encode(source); + if (version == null) { + return RawJsonDocument.create(source.getId(), source.getExpiration(), encodedContent); + } + else { + return RawJsonDocument.create(source.getId(), source.getExpiration(), encodedContent, version); } } - @Override - public void save(final Object objectToSave) { - save(objectToSave, PersistTo.ZERO, ReplicateTo.ZERO); - } - @Override - public void save(final Collection batchToSave) { - for (final Object toSave : batchToSave) { - save(toSave); - } - } - - @Override - public void update(final Object objectToUpdate) { - update(objectToUpdate, PersistTo.ZERO, ReplicateTo.ZERO); - } - - @Override - public void update(final Collection batchToUpdate) { - for (final Object toUpdate : batchToUpdate) { - update(toUpdate); - } - } - - @Override - public final T findById(final String id, final Class entityClass) { - CASValue result = execute(new BucketCallback() { - @Override - public CASValue doInBucket() { - return client.gets(id); - } - }); - - if (result == null) { - return null; - } - - final CouchbaseDocument converted = new CouchbaseDocument(id); - Object readEntity = couchbaseConverter.read(entityClass, (CouchbaseDocument) translateDecode( - (String) result.getValue(), converted)); - - final BeanWrapper 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 List findByView(final String designName, final String viewName, final Query query, final Class entityClass) { - - if (query.willIncludeDocs()) { - query.setIncludeDocs(false); - } - if (query.willReduce()) { - query.setReduce(false); - } - - final ViewResponse response = queryView(designName, viewName, query); - - final List result = new ArrayList(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() { - @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 execute(final BucketCallback 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() { - @Override - public String doInBucket() { - return (String) client.get(id); - } - }); - return result != null; + /** + * Decode a {@link Document Document<String>} containing a JSON string + * into a {@link CouchbaseStorable} + */ + private CouchbaseStorable decodeAndUnwrap(final Document 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 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(objectToSave)); - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToSave, converted); - - maybeEmitEvent(new BeforeSaveEvent(objectToSave, converted)); - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - if (version == null) { - OperationFuture 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 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(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 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(objectToInsert)); - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToInsert, converted); - - maybeEmitEvent(new BeforeSaveEvent(objectToInsert, converted)); - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - OperationFuture 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(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 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(objectToUpdate)); - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToUpdate, converted); - - maybeEmitEvent(new BeforeSaveEvent(objectToUpdate, converted)); - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - if (version == null) { - return client.replace(converted.getId(), converted.getExpiration(), translateEncode(converted), persistTo, - replicateTo).get(); - } else { - OperationFuture 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(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(objectToRemove)); - if (objectToRemove instanceof String) { - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - return client.delete((String) objectToRemove, persistTo, replicateTo).get(); - } - }); - maybeEmitEvent(new AfterDeleteEvent(objectToRemove)); - return; - } - - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToRemove, converted); - - execute(new BucketCallback>() { - @Override - public OperationFuture doInBucket() { - return client.delete(converted.getId()); - } - }); - maybeEmitEvent(new AfterDeleteEvent(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 findById(final String id, Class entityClass) { + RawJsonDocument result = execute(new BucketCallback() { + @Override + public RawJsonDocument doInBucket() { + return client.get(id, RawJsonDocument.class); + } + }); + + return mapToEntity(id, result, entityClass); + } + + @Override + public List findByView(ViewQuery query, Class 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 allRows = response.allRows(); + + final List result = new ArrayList(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() { + @Override + public ViewResult doInBucket() { + return client.query(query); + } + }); + } + + @Override + public List findByN1QL(Query n1ql, Class entityClass) { + try { + QueryResult queryResult = queryN1QL(n1ql); + + if (queryResult.finalSuccess()) { + List allRows = queryResult.allRows(); + List result = new ArrayList(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() { + @Override + public QueryResult doInBucket() throws TimeoutException, ExecutionException, InterruptedException { + return client.query(query); + } + }); + } + + @Override + public boolean exists(final String id) { + return execute(new BucketCallback() { + @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 execute(BucketCallback 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 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(objectToPersist)); + final CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(objectToPersist, converted); + + maybeEmitEvent(new BeforeSaveEvent(objectToPersist, converted)); + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + Document doc = encodeAndWrap(converted, version); + Document 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(objectToPersist, converted)); + } + + private void doRemove(final Object objectToRemove, final PersistTo persistTo, final ReplicateTo replicateTo) { + ensureNotIterable(objectToRemove); + + maybeEmitEvent(new BeforeDeleteEvent(objectToRemove)); + if (objectToRemove instanceof String) { + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + RawJsonDocument deletedDoc = client.remove((String) objectToRemove, persistTo, replicateTo, + RawJsonDocument.class); + return deletedDoc != null; + } + }); + maybeEmitEvent(new AfterDeleteEvent(objectToRemove)); + return; + } + + final CouchbaseDocument converted = new CouchbaseDocument(); + converter.write(objectToRemove, converted); + + execute(new BucketCallback() { + @Override + public Boolean doInBucket() { + RawJsonDocument deletedDoc = client.remove(converted.getId(), persistTo, replicateTo + , RawJsonDocument.class); + return deletedDoc != null; + } + }); + maybeEmitEvent(new AfterDeleteEvent(objectToRemove)); + } + + private T mapToEntity(String id, Document data, Class entityClass) { + if (data == null) { + return null; + } + + final CouchbaseDocument converted = new CouchbaseDocument(id); + Object readEntity = converter.read(entityClass, (CouchbaseDocument) decodeAndUnwrap(data, converted)); + + final BeanWrapper 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; } } diff --git a/src/main/java/org/springframework/data/couchbase/core/OperationCancellationException.java b/src/main/java/org/springframework/data/couchbase/core/OperationCancellationException.java index 1eb960ed..933147f3 100644 --- a/src/main/java/org/springframework/data/couchbase/core/OperationCancellationException.java +++ b/src/main/java/org/springframework/data/couchbase/core/OperationCancellationException.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -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 */ diff --git a/src/main/java/org/springframework/data/couchbase/core/OperationInterruptedException.java b/src/main/java/org/springframework/data/couchbase/core/OperationInterruptedException.java index ae29899b..e3f1076a 100644 --- a/src/main/java/org/springframework/data/couchbase/core/OperationInterruptedException.java +++ b/src/main/java/org/springframework/data/couchbase/core/OperationInterruptedException.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -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 */ diff --git a/src/main/java/org/springframework/data/couchbase/core/WriteResultChecking.java b/src/main/java/org/springframework/data/couchbase/core/WriteResultChecking.java index d9e7a4d6..2b711107 100644 --- a/src/main/java/org/springframework/data/couchbase/core/WriteResultChecking.java +++ b/src/main/java/org/springframework/data/couchbase/core/WriteResultChecking.java @@ -1,11 +1,11 @@ /* - * Copyright 2013, 2014 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/AbstractCouchbaseConverter.java b/src/main/java/org/springframework/data/couchbase/core/convert/AbstractCouchbaseConverter.java index f8bb8340..58d8d9b4 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/AbstractCouchbaseConverter.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/AbstractCouchbaseConverter.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/ConverterRegistration.java b/src/main/java/org/springframework/data/couchbase/core/convert/ConverterRegistration.java index c6ce1e37..2b55fdcc 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/ConverterRegistration.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/ConverterRegistration.java @@ -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 diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseConverter.java b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseConverter.java index a8fb6b37..64ffa4fc 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseConverter.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseConverter.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -28,8 +28,8 @@ import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProper * @author Michael Nitschinger */ public interface CouchbaseConverter - extends EntityConverter, - CouchbasePersistentProperty, Object, CouchbaseDocument>, - CouchbaseWriter, - EntityReader { + extends EntityConverter, + CouchbasePersistentProperty, Object, CouchbaseDocument>, + CouchbaseWriter, + EntityReader { } diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseDocumentPropertyAccessor.java b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseDocumentPropertyAccessor.java index 9727b81f..824e8561 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseDocumentPropertyAccessor.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseDocumentPropertyAccessor.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +16,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. * diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseTypeMapper.java b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseTypeMapper.java index 105d0d47..93615e11 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseTypeMapper.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseTypeMapper.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseWriter.java b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseWriter.java index 5d5a6384..f8e9de8f 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseWriter.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/CouchbaseWriter.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,5 +24,5 @@ import org.springframework.data.convert.EntityWriter; * @author Michael Nitschinger */ public interface CouchbaseWriter extends - EntityWriter { + EntityWriter { } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/CustomConversions.java b/src/main/java/org/springframework/data/couchbase/core/convert/CustomConversions.java index bef04b59..29a16236 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/CustomConversions.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/CustomConversions.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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. - * + *

*

Types that can be mapped directly onto JSON are considered simple ones, because they neither need deeper * inspection nor nested conversion.

* @@ -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 pairs) { + Iterable pairs) { Assert.notNull(sourceType); Assert.notNull(pairs); diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/DateConverters.java b/src/main/java/org/springframework/data/couchbase/core/convert/DateConverters.java index 435534d0..f1e6a5eb 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/DateConverters.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/DateConverters.java @@ -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; } } diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java b/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java index 2c5f9326..004a241a 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/DefaultCouchbaseTypeMapper.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/MappingCouchbaseConverter.java b/src/main/java/org/springframework/data/couchbase/core/convert/MappingCouchbaseConverter.java index 5c809fa5..75919923 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/MappingCouchbaseConverter.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/MappingCouchbaseConverter.java @@ -1,11 +1,11 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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 read(final CouchbasePersistentEntity entity, final CouchbaseDocument source, final Object parent) { final DefaultSpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(source, spELContext); ParameterValueProvider 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 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 parameterProvider = - new PersistentEntityParameterValueProvider(entity, provider, parent); + new PersistentEntityParameterValueProvider(entity, provider, parent); return new ConverterAwareSpELExpressionParameterValueProvider(evaluator, conversionService, parameterProvider, - parent); + parent); } /** @@ -231,7 +244,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter */ @SuppressWarnings("unchecked") protected Map 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 wrapper = BeanWrapper.create(source, conversionService); + final BeanWrapper 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 source, final CouchbaseDocument target, - final TypeInformation type) { + final TypeInformation type) { for (Map.Entry 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 items = targetType.getType().isArray() ? new ArrayList() : 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 { + SpELExpressionParameterValueProvider { private final Object parent; @@ -757,7 +770,7 @@ public class MappingCouchbaseConverter extends AbstractCouchbaseConverter @Override protected T potentiallyConvertSpelValue(final Object object, - final Parameter parameter) { + final Parameter parameter) { return readValue(object, parameter.getType(), parent); } } diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationService.java b/src/main/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationService.java index 6c3b5881..228e8f6a 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationService.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationService.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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 decodeFragment(String source, Class target) { + try { + return objectMapper.readValue(source, target); + } + catch (IOException e) { + throw new RuntimeException("Cannot decode ad-hoc JSON", e); } } diff --git a/src/main/java/org/springframework/data/couchbase/core/convert/translation/TranslationService.java b/src/main/java/org/springframework/data/couchbase/core/convert/translation/TranslationService.java index 0c2df4e1..4e9cde91 100644 --- a/src/main/java/org/springframework/data/couchbase/core/convert/translation/TranslationService.java +++ b/src/main/java/org/springframework/data/couchbase/core/convert/translation/TranslationService.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,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 the target class. + * @return an ad-hoc instance of the decoded JSON into the corresponding "case" class. + */ + T decodeFragment(String source, Class target); } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java index 1b70f6b9..16f84223 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentEntity.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -31,7 +31,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; * @author Michael Nitschinger */ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity - implements CouchbasePersistentEntity, ApplicationContextAware { + implements CouchbasePersistentEntity, ApplicationContextAware { /** * Contains the evaluation context. @@ -40,6 +40,7 @@ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity typeInformation) { @@ -55,9 +56,9 @@ public class BasicCouchbasePersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity *

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.

* * @author Michael Nitschinger */ public class BasicCouchbasePersistentProperty - extends AnnotationBasedPersistentProperty - implements CouchbasePersistentProperty { + extends AnnotationBasedPersistentProperty + 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. - * + *

* 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; diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseDocument.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseDocument.java index d4ee881e..07a1de7f 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseDocument.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseDocument.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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. - * + *

*

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}.

- * + *

*

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.

@@ -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. - * + *

* 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 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. - * + *

*

Note that unlike {@link #export()}, the nested objects are not converted, so the "raw" map is returned.

* * @return the underlying payload. @@ -208,7 +210,7 @@ public class CouchbaseDocument implements CouchbaseStorable { /** * Returns the expiration time of the document. - * + *

* 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. - * + *

* 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. - * + *

*

If this is not the case, a {@link IllegalArgumentException} is * thrown.

* * @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 + + '}'; } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseList.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseList.java index 96c67f6a..ef791031 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseList.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseList.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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. - * + *

*

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.

*/ @@ -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. - * + *

* 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. - * + *

*

If this is not the case, a {@link IllegalArgumentException} is * thrown.

* * @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 + + '}'; } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java index 89730dda..36d677ee 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseMappingContext.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,9 @@ package org.springframework.data.couchbase.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, CouchbasePersistentProperty> - implements ApplicationContextAware { + extends AbstractMappingContext, 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; + } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentEntity.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentEntity.java index 7ce3e4bb..cfaf7e5e 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentEntity.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentEntity.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -24,13 +24,13 @@ import org.springframework.data.mapping.PersistentEntity; * @author Michael Nitschinger */ public interface CouchbasePersistentEntity extends - PersistentEntity { + PersistentEntity { /** * Returns the expiry time for the document. * * @return the expiration time. */ - int getExpiry(); + int getExpiry(); } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentProperty.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentProperty.java index be133dda..dd2cce4d 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentProperty.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbasePersistentProperty.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,7 +27,7 @@ public interface CouchbasePersistentProperty extends PersistentProperty * The field name can be different from the actual property name by using a custom annotation. */ String getFieldName(); diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseSimpleTypes.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseSimpleTypes.java index 7e83efe5..6d450894 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseSimpleTypes.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseSimpleTypes.java @@ -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> simpleTypes = new HashSet>(); - simpleTypes.add(CouchbaseDocument.class); - simpleTypes.add(CouchbaseList.class); + simpleTypes.add(RawJsonDocument.class); + simpleTypes.add(JsonArray.class); COUCHBASE_SIMPLE_TYPES = Collections.unmodifiableSet(simpleTypes); } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseStorable.java b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseStorable.java index 217fe348..088b1bb9 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseStorable.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/CouchbaseStorable.java @@ -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}. - * + *

* This interface will be extended in the future to refactor the needed infrastructure into the common interface. * * @author Michael Nitschinger diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/Document.java b/src/main/java/org/springframework/data/couchbase/core/mapping/Document.java index 0d5cf7f3..4dff8e6b 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/Document.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/Document.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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. */ diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/Field.java b/src/main/java/org/springframework/data/couchbase/core/mapping/Field.java index 2793dc69..5bb09e30 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/Field.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/Field.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListener.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListener.java index f96cc187..d947add2 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListener.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListener.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -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 implements ApplicationListener 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()); } } diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterDeleteEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterDeleteEvent.java index 607ef88a..29c850c8 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterDeleteEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterDeleteEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterSaveEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterSaveEvent.java index 517ec20d..174ce998 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterSaveEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/AfterSaveEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeConvertEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeConvertEvent.java index 8a6fec1e..c1055abd 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeConvertEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeConvertEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeDeleteEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeDeleteEvent.java index 9cc83ba8..e5a15760 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeDeleteEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeDeleteEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeSaveEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeSaveEvent.java index 397cc7ca..0cbe7451 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeSaveEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/BeforeSaveEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/CouchbaseMappingEvent.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/CouchbaseMappingEvent.java index de5da3d4..c2a975be 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/CouchbaseMappingEvent.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/CouchbaseMappingEvent.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/LoggingEventListener.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/LoggingEventListener.java index 4793fbe6..9edaa2e7 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/LoggingEventListener.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/LoggingEventListener.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -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 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) { diff --git a/src/main/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListener.java b/src/main/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListener.java index 353bebd2..9860fc58 100644 --- a/src/main/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListener.java +++ b/src/main/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListener.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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()) { diff --git a/src/main/java/org/springframework/data/couchbase/core/package-info.java b/src/main/java/org/springframework/data/couchbase/core/package-info.java new file mode 100644 index 00000000..ddb60dfc --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/core/package-info.java @@ -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. + *
+ * 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; \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/monitor/AbstractMonitor.java b/src/main/java/org/springframework/data/couchbase/monitor/AbstractMonitor.java deleted file mode 100644 index 531dc944..00000000 --- a/src/main/java/org/springframework/data/couchbase/monitor/AbstractMonitor.java +++ /dev/null @@ -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 available = (ArrayList) client.getAvailableServers(); - Collections.shuffle(available); - return ((InetSocketAddress) available.get(0)).getHostName(); - } - - /** - * Fetches stats for all nodes. - * - * @return stats for each node - */ - protected Map> getStats() { - return client.getStats(); - } - - /** - * Returns stats for an individual node. - */ - protected Map getStats(SocketAddress node) { - return getStats().get(node); - } - -} diff --git a/src/main/java/org/springframework/data/couchbase/monitor/ClientInfo.java b/src/main/java/org/springframework/data/couchbase/monitor/ClientInfo.java index ba863f39..ad8f0e99 100644 --- a/src/main/java/org/springframework/data/couchbase/monitor/ClientInfo.java +++ b/src/main/java/org/springframework/data/couchbase/monitor/ClientInfo.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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 } diff --git a/src/main/java/org/springframework/data/couchbase/monitor/ClusterInfo.java b/src/main/java/org/springframework/data/couchbase/monitor/ClusterInfo.java index a9e5700e..282d0fc9 100644 --- a/src/main/java/org/springframework/data/couchbase/monitor/ClusterInfo.java +++ b/src/main/java/org/springframework/data/couchbase/monitor/ClusterInfo.java @@ -1,11 +1,11 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2012-2015 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,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 available = info.nodeList(); + Collections.shuffle(available); + return available.get(0).getHostName(); + } + private HashMap fetchPoolInfo() { - return getTemplate().getForObject("http://" - + randomAvailableHostname() + ":8091/pools/default", HashMap.class); + return template.getForObject("http://" + + randomAvailableHostname() + ":8091/pools/default", HashMap.class); } private HashMap parseStorageTotals() { HashMap stats = fetchPoolInfo(); - return (HashMap) stats.get("storageTotals"); + return (HashMap) stats.get("storageTotals"); } } diff --git a/src/main/java/org/springframework/data/couchbase/monitor/package-info.java b/src/main/java/org/springframework/data/couchbase/monitor/package-info.java new file mode 100644 index 00000000..d64a4c07 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/monitor/package-info.java @@ -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; \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/repository/package-info.java b/src/main/java/org/springframework/data/couchbase/repository/package-info.java new file mode 100644 index 00000000..b01e083a --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/repository/package-info.java @@ -0,0 +1,7 @@ +/** + * This package contains the Couchbase implementation to support the Spring Data repository abstraction. + *
+ * 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; \ No newline at end of file diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/ViewBasedCouchbaseQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/ViewBasedCouchbaseQuery.java index ee74bd8a..d37e8bfc 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/ViewBasedCouchbaseQuery.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/ViewBasedCouchbaseQuery.java @@ -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 diff --git a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java index fea6205e..50e97488 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java +++ b/src/main/java/org/springframework/data/couchbase/repository/support/SimpleCouchbaseRepository.java @@ -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 implements Co @Override public Iterable 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 findAll(final Iterable 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 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()); } } diff --git a/src/main/resources/META-INF/spring.schemas b/src/main/resources/META-INF/spring.schemas index 349e29ce..6b43469e 100644 --- a/src/main/resources/META-INF/spring.schemas +++ b/src/main/resources/META-INF/spring.schemas @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/src/main/resources/changelog.txt b/src/main/resources/changelog.txt index 7806f98a..76739127 100644 --- a/src/main/resources/changelog.txt +++ b/src/main/resources/changelog.txt @@ -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 \ No newline at end of file diff --git a/src/main/resources/notice.txt b/src/main/resources/notice.txt index a728bdd0..942ed0ad 100644 --- a/src/main/resources/notice.txt +++ b/src/main/resources/notice.txt @@ -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. \ No newline at end of file diff --git a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd new file mode 100644 index 00000000..669cb5f1 --- /dev/null +++ b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The reference to a Bucket object. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-env-2.0.xsd b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-env-2.0.xsd new file mode 100644 index 00000000..91e8f61f --- /dev/null +++ b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-env-2.0.xsd @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/springframework/data/couchbase/BucketCreator.java b/src/test/java/org/springframework/data/couchbase/BucketCreator.java deleted file mode 100644 index 151d1d9c..00000000 --- a/src/test/java/org/springframework/data/couchbase/BucketCreator.java +++ /dev/null @@ -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 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(); - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/TestApplicationConfig.java b/src/test/java/org/springframework/data/couchbase/TestApplicationConfig.java deleted file mode 100644 index 7ce4257c..00000000 --- a/src/test/java/org/springframework/data/couchbase/TestApplicationConfig.java +++ /dev/null @@ -1,94 +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; - -import com.couchbase.client.CouchbaseClient; -import com.couchbase.client.CouchbaseConnectionFactoryBuilder; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; -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; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Michael Nitschinger - */ -@Configuration -public class TestApplicationConfig extends AbstractCouchbaseConfiguration { - - @Autowired - private Environment env; - - @Bean - public String couchbaseAdminUser() { - return env.getProperty("couchbase.adminUser", "Administrator"); - } - - @Bean - public String couchbaseAdminPassword() { - return env.getProperty("couchbase.adminUser", "password"); - } - - @Override - protected List bootstrapHosts() { - return Arrays.asList(env.getProperty("couchbase.host", "127.0.0.1")); - } - - @Override - protected String getBucketName() { - return env.getProperty("couchbase.bucket", "default"); - } - - @Override - protected String getBucketPassword() { - return env.getProperty("couchbase.password", ""); - } - - @Bean - public BucketCreator bucketCreator() throws Exception { - return new BucketCreator(bootstrapHosts().get(0), couchbaseAdminUser(), couchbaseAdminPassword()); - } - - @Bean - @Override - @DependsOn("bucketCreator") - public CouchbaseClient couchbaseClient() throws Exception { - setLoggerProperty(couchbaseLogger()); - - CouchbaseConnectionFactoryBuilder builder = new CouchbaseConnectionFactoryBuilder(); - builder.setOpTimeout(10000); // using a higher timeout for tests to reduce flakiness - - return new CouchbaseClient(builder.buildCouchbaseConnection( - bootstrapUris(bootstrapHosts()), - getBucketName(), - getBucketPassword() - )); - } - - @Override - public CouchbaseTemplate couchbaseTemplate() throws Exception { - CouchbaseTemplate template = super.couchbaseTemplate(); - template.setWriteResultChecking(WriteResultChecking.LOG); - return template; - } -} diff --git a/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java b/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java new file mode 100644 index 00000000..62be5f77 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/UnitTestApplicationConfig.java @@ -0,0 +1,67 @@ +package org.springframework.data.couchbase; + +import java.util.Collections; +import java.util.List; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseBucket; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import org.mockito.Mock; +import org.mockito.Mockito; + +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 UnitTestApplicationConfig extends AbstractCouchbaseConfiguration { + + @Bean + public String couchbaseAdminUser() { + return "someLogin"; + } + + @Bean + public String couchbaseAdminPassword() { + return "somePassword"; + } + + @Override + protected List getBootstrapHosts() { + return Collections.singletonList("192.1.2.3"); + } + + @Override + protected String getBucketName() { + return "someBucket"; + } + + @Override + protected String getBucketPassword() { + return "someBucketPassword"; + } + + @Override + public Cluster couchbaseCluster() throws Exception { + return Mockito.mock(CouchbaseCluster.class); + } + + @Override + public Bucket couchbaseClient() throws Exception { + return Mockito.mock(CouchbaseBucket.class); + } + + @Override + public CouchbaseTemplate couchbaseTemplate() throws Exception { + CouchbaseTemplate template = super.couchbaseTemplate(); + template.setWriteResultChecking(WriteResultChecking.LOG); + return template; + } +} diff --git a/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheManagerTests.java b/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheManagerTests.java deleted file mode 100644 index 46f4e377..00000000 --- a/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheManagerTests.java +++ /dev/null @@ -1,110 +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.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.Cache; -import org.springframework.data.couchbase.TestApplicationConfig; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import java.util.HashMap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * Verifies the correct functionality of the CouchbaseCacheManager. - * - * @author Michael Nitschinger - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) -public class CouchbaseCacheManagerTests { - - /** - * Contains a reference to the actual CouchbaseClient. - */ - @Autowired - private CouchbaseClient client; - - /** - * Tests the main functionality of the manager: loading the caches. - */ - @Test - public void testCacheInit() { - HashMap instances = - new HashMap(); - instances.put("test", client); - - CouchbaseCacheManager manager = new CouchbaseCacheManager(instances); - manager.afterPropertiesSet(); - - assertEquals(instances, manager.getClients()); - - Cache cache = manager.getCache("test"); - - assertNotNull(cache); - - assertEquals(cache.getClass(), CouchbaseCache.class); - assertEquals(((CouchbaseCache) cache).getName(), "test"); - assertEquals(((CouchbaseCache) cache).getTtl(), 0); // default TTL value - assertEquals(((CouchbaseCache) cache).getNativeCache(), client); - } - - /** - * Test cache creation with custom TTL values. - */ - @Test - public void testCacheInitWithTtl() { - HashMap instances = new HashMap(); - instances.put("cache1", client); - instances.put("cache2", client); - - HashMap ttlConfiguration = new HashMap(); - ttlConfiguration.put("cache1", 100); - ttlConfiguration.put("cache2", 200); - - CouchbaseCacheManager manager = new CouchbaseCacheManager(instances, ttlConfiguration); - manager.afterPropertiesSet(); - - assertEquals(instances, manager.getClients()); - - Cache cache1 = manager.getCache("cache1"); - Cache cache2 = manager.getCache("cache2"); - - assertNotNull(cache1); - assertNotNull(cache2); - - assertEquals(cache1.getClass(), CouchbaseCache.class); - assertEquals(cache2.getClass(), CouchbaseCache.class); - - assertEquals(((CouchbaseCache) cache1).getName(), "cache1"); - assertEquals(((CouchbaseCache) cache2).getName(), "cache2"); - - assertEquals(((CouchbaseCache) cache1).getTtl(), 100); - assertEquals(((CouchbaseCache) cache2).getTtl(), 200); - - assertEquals(((CouchbaseCache) cache1).getNativeCache(), client); - assertEquals(((CouchbaseCache) cache2).getNativeCache(), client); - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheTests.java b/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheTests.java deleted file mode 100644 index 62ef68a3..00000000 --- a/src/test/java/org/springframework/data/couchbase/cache/CouchbaseCacheTests.java +++ /dev/null @@ -1,158 +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.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.Cache.ValueWrapper; -import org.springframework.data.couchbase.TestApplicationConfig; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import java.io.Serializable; - -import static org.junit.Assert.*; - -/** - * Tests the CouchbaseCache class and verifies its functionality. - * - * @author Michael Nitschinger - * @author Konrad Król - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) -public class CouchbaseCacheTests { - - /** - * Contains a reference to the actual CouchbaseClient. - */ - @Autowired - private CouchbaseClient client; - - /** - * Simple name of the cache bucket to create. - */ - private String cacheName = "test"; - - /** - * Tests the basic Cache construction functionality. - */ - @Test - public void testConstruction() { - CouchbaseCache cache = new CouchbaseCache(cacheName, client); - - assertEquals(cacheName, cache.getName()); - assertEquals(client, cache.getNativeCache()); - } - - /** - * Verifies set() and get() of cache objects. - */ - @Test - public void testGetSet() { - CouchbaseCache cache = new CouchbaseCache(cacheName, client); - - String key = "couchbase-cache-test"; - String value = "Hello World!"; - cache.put(key, value); - - String stored = (String) client.get(key); - assertNotNull(stored); - assertEquals(value, stored); - - ValueWrapper loaded = cache.get(key); - assertEquals(value, loaded.get()); - } - - /** - * Verifies set() with TTL value. - */ - @Test - public void testSetWithTtl() throws InterruptedException { - CouchbaseCache cache = new CouchbaseCache(cacheName, client, 1); // cache for 1 second - - String key = "couchbase-cache-test"; - String value = "Hello World!"; - cache.put(key, value); - - // wait for TTL to expire (double time of TTL) - Thread.sleep(2000); - - String stored = (String) client.get(key); - assertNull(stored); - } - - @Test - public void testGetSetWithCast() { - CouchbaseCache cache = new CouchbaseCache(cacheName, client); - - String key = "couchbase-cache-user"; - User user = new User(); - user.firstname = "Michael"; - - cache.put(key, user); - - User loaded = cache.get(key, User.class); - assertNotNull(loaded); - assertEquals(user.firstname, loaded.firstname); - } - - /** - * Verifies the deletion of cache objects. - * - * @throws Exception - */ - @Test - public void testEvict() throws Exception { - CouchbaseCache cache = new CouchbaseCache(cacheName, client); - - String key = "couchbase-cache-test"; - String value = "Hello World!"; - - Boolean success = client.set(key, 0, value).get(); - assertTrue(success); - - cache.evict(key); - Object result = client.get(key); - assertNull(result); - } - - /** - * Putting into cache on the same key not null value, and then null value, - * results in null object - */ - @Test - public void testSettingNullAndGetting() { - CouchbaseCache cache = new CouchbaseCache(cacheName, client); - - String key = "couchbase-cache-test"; - String value = "Hello World!"; - - cache.put(key, value); - cache.put(key, null); - - assertNull(cache.get(key)); - } - - static class User implements Serializable { - public String firstname; - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfigurationTests.java b/src/test/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfigurationTests.java deleted file mode 100644 index 36fc876c..00000000 --- a/src/test/java/org/springframework/data/couchbase/config/AbstractCouchbaseConfigurationTests.java +++ /dev/null @@ -1,86 +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.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.data.couchbase.TestApplicationConfig; -import org.springframework.data.couchbase.core.mapping.Document; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Unit test for {@link AbstractCouchbaseConfiguration} - * - * @author Michael Nitschinger - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) -public class AbstractCouchbaseConfigurationTests { - - /** - * Contains a reference to the actual CouchbaseClient. - */ - @Autowired - private CouchbaseClient client; - - @Test - public void usesConfigClassPackageAsBaseMappingPackage() throws Exception { - AbstractCouchbaseConfiguration config = new SampleCouchbaseConfiguration(); - assertEquals(config.getMappingBasePackage(), SampleCouchbaseConfiguration.class.getPackage().getName()); - assertEquals(config.getInitialEntitySet().size(), 1); - assertTrue(config.getInitialEntitySet().contains(Entity.class)); - } - - class SampleCouchbaseConfiguration extends AbstractCouchbaseConfiguration { - - @Override - protected List bootstrapHosts() { - return null; - } - - @Override - protected String getBucketName() { - return null; - } - - @Override - protected String getBucketPassword() { - return null; - } - - @Bean - @Override - public CouchbaseClient couchbaseClient() throws Exception { - return client; - } - } - - @Document - static class Entity { - - } -} diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java new file mode 100644 index 00000000..932e1d29 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java @@ -0,0 +1,136 @@ +/* + * 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.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.util.List; + +import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +public class CouchbaseBucketParserTest { + + + private static DefaultListableBeanFactory factory; + + @BeforeClass + public static void setUp() { + factory = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + int n = reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseBucket-bean.xml")); + System.out.println(n); + } + + @AfterClass + public static void tearDown() { + } + + @Test + public void testDefaultBucketNoCluster() { + BeanDefinition def = factory.getBeanDefinition("bucketDefaultNoCluster"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(clusterRef.getBeanName(), is(equalTo(BeanNames.COUCHBASE_CLUSTER))); + } + + @Test + public void testDefaultBucket() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketDefault"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + } + + @Test + public void testBucketWithName() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketWithName"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(2))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + + ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues() + .getArgumentValue(1, Object.class); + assertThat(nameHolder.getValue(), is(instanceOf(String.class))); + assertThat(nameHolder.getValue().toString(), is((equalTo("toto")))); + } + + @Test + public void testBucketWithNameAndPassword() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketWithNameAndPassword"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(3))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + + ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues() + .getArgumentValue(1, Object.class); + assertThat(nameHolder.getValue(), is(instanceOf(String.class))); + assertThat(nameHolder.getValue().toString(), is((equalTo("test")))); + + ConstructorArgumentValues.ValueHolder passwordHolder = def.getConstructorArgumentValues() + .getArgumentValue(2, Object.class); + assertThat(passwordHolder.getValue(), is(instanceOf(String.class))); + assertThat(passwordHolder.getValue().toString(), is((equalTo("123")))); + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseClusterParserTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseClusterParserTest.java new file mode 100644 index 00000000..1cfdcb16 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseClusterParserTest.java @@ -0,0 +1,154 @@ +/* + * 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.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.util.List; + +import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +public class CouchbaseClusterParserTest { + + + private static DefaultListableBeanFactory factory; + + @BeforeClass + public static void setUp() { + factory = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + int n = reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseCluster-bean.xml")); + System.out.println(n); + } + + @AfterClass + public static void tearDown() { + } + + @Test + public void testClusterWithoutSpecificEnv() { + BeanDefinition def = factory.getBeanDefinition("clusterDefault"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + assertThat(def.getFactoryMethodName(), is(equalTo("create"))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, CouchbaseEnvironment.class); + + assertThat(holder.getValue(), instanceOf(RuntimeBeanReference.class)); + RuntimeBeanReference envRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(envRef.getBeanName(), is(equalTo("couchbaseEnv"))); + } + + @Test + public void testClusterWithNodes() { + BeanDefinition def = factory.getBeanDefinition("clusterWithNodes"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(2))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + assertThat(def.getFactoryMethodName(), is(equalTo("create"))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(1, List.class); + assertThat(holder.getValue(), is(instanceOf(List.class))); + List nodes = (List) holder.getValue(); + + assertThat(nodes.size(), is(equalTo(2))); + assertThat((String) nodes.get(0), is(equalTo("192.1.2.3"))); + assertThat((String) nodes.get(1), is(equalTo("192.4.5.6"))); + } + + @Test + public void testClusterWithEnvInline() { + BeanDefinition def = factory.getBeanDefinition("clusterWithEnvInline"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, CouchbaseEnvironment.class); + GenericBeanDefinition envDef = (GenericBeanDefinition) holder.getValue(); + + assertThat(envDef.getBeanClassName(), is(equalTo(CouchbaseEnvironmentFactoryBean.class.getName()))); + assertThat("unexpected attribute", envDef.getPropertyValues().contains("managementTimeout")); + } + + @Test + public void testClusterWithEnvRef() { + BeanDefinition def = factory.getBeanDefinition("clusterWithEnvRef"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, CouchbaseEnvironment.class); + + assertThat(holder.getValue(), instanceOf(RuntimeBeanReference.class)); + RuntimeBeanReference envRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(envRef.getBeanName(), is(equalTo("someEnv"))); + } + @Test + public void testClusterConfigurationPrecedence() { + BeanDefinition def = factory.getBeanDefinition("clusterWithAll"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(2))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + assertThat(def.getFactoryMethodName(), is(equalTo("create"))); + + assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(0).getValue(), + instanceOf(GenericBeanDefinition.class)); + assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(1).getValue(), + instanceOf(List.class)); + + ConstructorArgumentValues.ValueHolder holderEnv = def.getConstructorArgumentValues() + .getArgumentValue(0, CouchbaseEnvironment.class); + GenericBeanDefinition envDef = (GenericBeanDefinition) holderEnv.getValue(); + + assertThat(envDef.getBeanClassName(), is(equalTo(CouchbaseEnvironmentFactoryBean.class.getName()))); + assertThat("unexpected attribute", envDef.getPropertyValues().contains("autoreleaseAfter")); + + ConstructorArgumentValues.ValueHolder holderNodes = def.getConstructorArgumentValues() + .getArgumentValue(1, List.class); + List nodes = (List) holderNodes.getValue(); + + assertThat(nodes.size(), is(equalTo(2))); + assertThat((String) nodes.get(0), is(equalTo("2.2.2.2"))); + assertThat((String) nodes.get(1), is(equalTo("4.4.4.4"))); + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParserTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParserTest.java new file mode 100644 index 00000000..ad0766f2 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseEnvironmentParserTest.java @@ -0,0 +1,109 @@ +/* + * 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.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertThat; + +import com.couchbase.client.core.retry.BestEffortRetryStrategy; +import com.couchbase.client.core.retry.FailFastRetryStrategy; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.io.ClassPathResource; + +public class CouchbaseEnvironmentParserTest { + + private static GenericApplicationContext context; + + @BeforeClass + public static void setUp() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseEnv-bean.xml")); + context = new GenericApplicationContext(factory); + context.refresh(); + } + + @Test + public void testParsingRetryStrategyFailFast() throws Exception { + CouchbaseEnvironment env = context.getBean("envWithFailFast", CouchbaseEnvironment.class); + + assertThat(env.retryStrategy(), is(instanceOf(FailFastRetryStrategy.class))); + } + + @Test + public void testParsingRetryStrategyBestEffort() throws Exception { + CouchbaseEnvironment env = context.getBean("envWithBestEffort", CouchbaseEnvironment.class); + + assertThat(env.retryStrategy(), is(instanceOf(BestEffortRetryStrategy.class))); + } + + @Test + public void testAllDefaultsOverridden() { + CouchbaseEnvironment env = context.getBean("envWithNoDefault", CouchbaseEnvironment.class); + CouchbaseEnvironment defaultEnv = DefaultCouchbaseEnvironment.create(); + + assertThat(env, is(instanceOf(DefaultCouchbaseEnvironment.class))); + + assertThat(env.managementTimeout(), is(equalTo(1L))); + assertThat(env.queryTimeout(), is(equalTo(2L))); + assertThat(env.viewTimeout(), is(equalTo(3L))); + assertThat(env.kvTimeout(), is(equalTo(4L))); + assertThat(env.connectTimeout(), is(equalTo(5L))); + assertThat(env.disconnectTimeout(), is(equalTo(6L))); + assertThat(env.dnsSrvEnabled(), allOf(equalTo(true), not(defaultEnv.dnsSrvEnabled()))); + + //TODO activate test when dcp can be enabled on the environment (add it in the xml) +// assertThat(env.dcpEnabled(), allOf(equalTo(true), not(defaultEnv.dcpEnabled()))); + assertThat(env.sslEnabled(), allOf(equalTo(true), not(defaultEnv.sslEnabled()))); + assertThat(env.sslKeystoreFile(), is(equalTo("test"))); + assertThat(env.sslKeystorePassword(), is(equalTo("test"))); + assertThat(env.queryEnabled(), allOf(equalTo(true), not(defaultEnv.queryEnabled()))); + assertThat(env.queryPort(), is(equalTo(7))); + assertThat(env.bootstrapHttpEnabled(), allOf(equalTo(false), not(defaultEnv.bootstrapHttpEnabled()))); + assertThat(env.bootstrapCarrierEnabled(), allOf(equalTo(false), not(defaultEnv.bootstrapCarrierEnabled()))); + assertThat(env.bootstrapHttpDirectPort(), is(equalTo(8))); + assertThat(env.bootstrapHttpSslPort(), is(equalTo(9))); + assertThat(env.bootstrapCarrierDirectPort(), is(equalTo(10))); + assertThat(env.bootstrapCarrierSslPort(), is(equalTo(11))); + assertThat(env.ioPoolSize(), is(equalTo(12))); + assertThat(env.computationPoolSize(), is(equalTo(13))); + assertThat(env.responseBufferSize(), is(equalTo(14))); + assertThat(env.requestBufferSize(), is(equalTo(15))); + assertThat(env.kvEndpoints(), is(equalTo(16))); + assertThat(env.viewEndpoints(), is(equalTo(17))); + assertThat(env.queryEndpoints(), is(equalTo(18))); + assertThat(env.retryStrategy(), is(instanceOf(FailFastRetryStrategy.class))); + assertThat(env.maxRequestLifetime(), is(equalTo(19L))); + assertThat(env.keepAliveInterval(), is(equalTo(20L))); + assertThat(env.autoreleaseAfter(), is(equalTo(21L))); + assertThat(env.bufferPoolingEnabled(), allOf(equalTo(false), not(defaultEnv.bufferPoolingEnabled()))); + } + + @AfterClass + public static void tearDown() { + context.close(); + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTests.java deleted file mode 100644 index 7b25521b..00000000 --- a/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTests.java +++ /dev/null @@ -1,43 +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 org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.junit.Assert.*; - -/** - * @author Michael Nitschinger - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath:namespace/couchbase-bean.xml") -public class CouchbaseParserIntegrationTests { - @Autowired - ApplicationContext ctx; - - @Test - public void readsCouchbaseAttributesCorrectly() { - assertTrue(ctx.containsBean("couchbase")); - assertTrue(ctx.containsBean("couchbase2")); - assertTrue(ctx.containsBean("couchbase3")); - } -} diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java deleted file mode 100644 index 426e0f26..00000000 --- a/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTests.java +++ /dev/null @@ -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.config; - -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; - -import static org.junit.Assert.assertEquals; - -/** - * @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("namespace/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("namespace/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("namespace/couchbase-multi-bucket-bean.xml")); - - factory.getBean("cb-template-first"); - factory.getBean("cb-template-second"); - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/core/Beer.java b/src/test/java/org/springframework/data/couchbase/core/Beer.java index b6900de8..e801c296 100644 --- a/src/test/java/org/springframework/data/couchbase/core/Beer.java +++ b/src/test/java/org/springframework/data/couchbase/core/Beer.java @@ -61,9 +61,9 @@ public class Beer { public boolean getActive() { return active; } - + public String getId() { - return id; + return id; } } diff --git a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java b/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java deleted file mode 100644 index 0f3f5aad..00000000 --- a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateTests.java +++ /dev/null @@ -1,536 +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.protocol.views.Query; -import com.couchbase.client.protocol.views.Stale; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import net.spy.memcached.CASValue; -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.TestApplicationConfig; -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; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * @author Michael Nitschinger - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) -@TestExecutionListeners(CouchbaseTemplateViewListener.class) -public class CouchbaseTemplateTests { - - @Autowired - private CouchbaseClient client; - - @Autowired - private CouchbaseTemplate template; - - private static final ObjectMapper MAPPER = new ObjectMapper(); - - @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); - String result = (String) client.get(id); - assertNotNull(result); - Map resultConv = MAPPER.readValue(result, new TypeReference>() {}); - - 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"; - client.delete(id).get(); - - SimplePerson doc = new SimplePerson(id, "Mr. A"); - template.insert(doc); - String result = (String) client.get(id); - - Map resultConv = MAPPER.readValue(result, new TypeReference>() {}); - assertEquals("Mr. A", resultConv.get("name")); - - doc = new SimplePerson(id, "Mr. B"); - template.insert(doc); - result = (String) client.get(id); - - resultConv = MAPPER.readValue(result, new TypeReference>() {}); - 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 names = new ArrayList(); - names.add("Michael"); - names.add("Thomas"); - names.add(null); - List votes = new LinkedList(); - Map info1 = new HashMap(); - info1.put("foo", true); - info1.put("bar", false); - info1.put("nullValue", null); - Map info2 = new HashMap(); - - 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() { - Query query = new Query(); - query.setStale(Stale.FALSE); - - final List beers = template.findByView("test_beers", "by_name", query, Beer.class); - assertTrue(beers.size() > 0); - - for (Beer beer : beers) { - assertNotNull(beer.getId()); - assertNotNull(beer.getName()); - assertNotNull(beer.getActive()); - } - } - - @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 { - client.delete("versionedClass:1").get(); - - VersionedClass versionedClass = new VersionedClass("versionedClass:1", "foobar"); - assertEquals(0, versionedClass.getVersion()); - template.insert(versionedClass); - CASValue rawStored = client.gets("versionedClass:1"); - assertEquals(rawStored.getCas(), versionedClass.getVersion()); - } - - @Test - public void versionShouldNotUpdateOnSecondInsert() throws Exception { - client.delete("versionedClass:2").get(); - - 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 { - client.delete("versionedClass:3").get(); - - 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 { - client.delete("versionedClass:4").get(); - - VersionedClass versionedClass = new VersionedClass("versionedClass:4", "foobar"); - template.insert(versionedClass); - - assertTrue(client.set("versionedClass:4", "different").get()); - - versionedClass.setField("foobar2"); - template.save(versionedClass); - } - - @Test - public void shouldUpdateDocumentOnMatchingVersion() throws Exception { - client.delete("versionedClass:5").get(); - - 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 { - client.delete("versionedClass:6").get(); - - VersionedClass versionedClass = new VersionedClass("versionedClass:6", "foobar"); - template.insert(versionedClass); - - assertTrue(client.set("versionedClass:6", "different").get()); - - versionedClass.setField("foobar2"); - template.update(versionedClass); - } - - @Test - public void shouldLoadVersionPropertyOnFind() throws Exception { - client.delete("versionedClass:7").get(); - - 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 firstnames; - @Field - private final List votes; - - @Field - private final Map info1; - @Field - private final Map info2; - - public ComplexPerson(String id, List firstnames, - List votes, Map info1, - Map info2) { - this.id = id; - this.firstnames = firstnames; - this.votes = votes; - this.info1 = info1; - this.info2 = info2; - } - - List getFirstnames() { - return firstnames; - } - - List getVotes() { - return votes; - } - - Map getInfo1() { - return info1; - } - - Map 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 integerClass; - - private String value; - - SimpleWithClass(final String id, final Class integerClass) { - this.id = id; - this.integerClass = integerClass; - } - - String getId() { - return id; - } - - void setId(final String id) { - this.id = id; - } - - Class getIntegerClass() { - return integerClass; - } - - void setIntegerClass(final Class 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; - } - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java b/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java deleted file mode 100644 index 0ecaf8be..00000000 --- a/src/test/java/org/springframework/data/couchbase/core/CouchbaseTemplateViewListener.java +++ /dev/null @@ -1,54 +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.protocol.views.DesignDocument; -import com.couchbase.client.protocol.views.ViewDesign; -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 { - CouchbaseClient client = (CouchbaseClient) testContext.getApplicationContext().getBean("couchbaseClient"); - populateTestData(client); - createAndWaitForDesignDocs(client); - } - - private void populateTestData(CouchbaseClient 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(CouchbaseClient client) { - DesignDocument designDoc = new DesignDocument("test_beers"); - String mapFunction = "function (doc, meta) { if(doc._class == " - + "\"org.springframework.data.couchbase.core.Beer\") { emit(doc.name, null); } }"; - designDoc.setView(new ViewDesign("by_name", mapFunction)); - client.createDesignDoc(designDoc); - } - -} diff --git a/src/test/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationServiceTests.java b/src/test/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationServiceTests.java index f52d51b8..a53ea010 100644 --- a/src/test/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationServiceTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/convert/translation/JacksonTranslationServiceTests.java @@ -16,11 +16,13 @@ package org.springframework.data.couchbase.core.convert.translation; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import org.junit.Before; import org.junit.Test; -import org.springframework.data.couchbase.core.mapping.CouchbaseDocument; -import static org.junit.Assert.assertEquals; +import org.springframework.data.couchbase.core.mapping.CouchbaseDocument; /** * Verifies the functionality of a {@link JacksonTranslationService}. @@ -29,26 +31,39 @@ import static org.junit.Assert.assertEquals; */ public class JacksonTranslationServiceTests { - private TranslationService service; + private TranslationService service; - @Before - public void setup() { - service = new JacksonTranslationService(); - } + @Before + public void setup() { + service = new JacksonTranslationService(); + ((JacksonTranslationService) service).afterPropertiesSet(); + } - @Test - public void shouldEncodeNonASCII() { - CouchbaseDocument doc = new CouchbaseDocument("key"); - doc.put("language", "русский"); - String expected = "{\"language\":\"русский\"}"; - assertEquals(expected, service.encode(doc)); - } + @Test + public void shouldEncodeNonASCII() { + CouchbaseDocument doc = new CouchbaseDocument("key"); + doc.put("language", "русский"); + String expected = "{\"language\":\"русский\"}"; + assertEquals(expected, service.encode(doc)); + } - @Test - public void shouldDecodeNonASCII() { - String source = "{\"language\":\"русский\"}"; - CouchbaseDocument target = new CouchbaseDocument(); - service.decode(source, target); - assertEquals("русский", target.get("language")); - } + @Test + public void shouldDecodeNonASCII() { + String source = "{\"language\":\"русский\"}"; + CouchbaseDocument target = new CouchbaseDocument(); + service.decode(source, target); + assertEquals("русский", target.get("language")); + } + + @Test + public void shouldDecodeAdHocFragment() { + String source = "{\"language\":\"french\"}"; + LanguageFragment f = service.decodeFragment(source, LanguageFragment.class); + assertNotNull(f); + assertEquals("french", f.language); + } + + private static class LanguageFragment { + public String language; + } } diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java index 9d9f9e6a..3c108e96 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/BasicCouchbasePersistentPropertyTests.java @@ -16,18 +16,19 @@ package org.springframework.data.couchbase.core.mapping; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Field; + import org.junit.Before; import org.junit.Test; + import org.springframework.data.annotation.Id; import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Field; - -import static org.junit.Assert.assertEquals; - /** * Verifies the correct behavior of properties on persistable objects. * @@ -46,7 +47,7 @@ public class BasicCouchbasePersistentPropertyTests { @Before public void setUp() { entity = new BasicCouchbasePersistentEntity( - ClassTypeInformation.from(Beer.class)); + ClassTypeInformation.from(Beer.class)); } /** @@ -75,7 +76,7 @@ public class BasicCouchbasePersistentPropertyTests { */ private CouchbasePersistentProperty getPropertyFor(Field field) { return new BasicCouchbasePersistentProperty(field, null, entity, - new SimpleTypeHolder(), PropertyNameFieldNamingStrategy.INSTANCE); + new SimpleTypeHolder(), PropertyNameFieldNamingStrategy.INSTANCE); } /** diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/CustomConvertersTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/CustomConvertersTests.java index fb36e8b4..f0879aaa 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/CustomConvertersTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/CustomConvertersTests.java @@ -16,34 +16,37 @@ package org.springframework.data.couchbase.core.mapping; +import static org.junit.Assert.assertEquals; + +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.converter.Converter; - import org.springframework.data.annotation.Id; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; -import org.springframework.data.couchbase.TestApplicationConfig; +import org.springframework.data.couchbase.UnitTestApplicationConfig; import org.springframework.data.couchbase.core.convert.CustomConversions; import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.text.Format; -import java.text.SimpleDateFormat; -import java.util.*; - -import static org.junit.Assert.assertEquals; - /** * Tests to verify custom mapping logic. * * @author Michael Nitschinger */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) +@ContextConfiguration(classes = UnitTestApplicationConfig.class) public class CustomConvertersTests { @Autowired @@ -161,9 +164,9 @@ public class CustomConvertersTests { @Override public CouchbaseDocument convert(BlogPost source) { return new CouchbaseDocument() - .setId(source.id) - .put("title", source.title) - .put("slug", source.title.toLowerCase().replaceAll(" ", "_")); + .setId(source.id) + .put("title", source.title) + .put("slug", source.title.toLowerCase().replaceAll(" ", "_")); } } diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java index 7e3b8286..ca3f92da 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/MappingCouchbaseConverterTests.java @@ -16,20 +16,7 @@ package org.springframework.data.couchbase.core.mapping; -import org.joda.time.LocalDateTime; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.convert.converter.Converter; -import org.springframework.data.annotation.Id; -import org.springframework.data.couchbase.TestApplicationConfig; -import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; -import org.springframework.data.mapping.model.MappingException; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.data.couchbase.core.convert.CustomConversions; -import org.springframework.data.convert.ReadingConverter; -import org.springframework.data.convert.WritingConverter; +import static org.junit.Assert.*; import java.math.BigDecimal; import java.util.ArrayList; @@ -46,15 +33,27 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import org.joda.time.LocalDateTime; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.annotation.Id; +import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; +import org.springframework.data.couchbase.UnitTestApplicationConfig; +import org.springframework.data.couchbase.core.convert.CustomConversions; +import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; +import org.springframework.data.mapping.model.MappingException; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Michael Nitschinger */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = TestApplicationConfig.class) +@ContextConfiguration(classes = UnitTestApplicationConfig.class) public class MappingCouchbaseConverterTests { @Autowired @@ -86,7 +85,7 @@ public class MappingCouchbaseConverterTests { @Test(expected = MappingException.class) public void needsIDOnEntity() { converter.write(new EntityWithoutID("foo"), - new CouchbaseDocument()); + new CouchbaseDocument()); } @Test @@ -226,7 +225,7 @@ public class MappingCouchbaseConverterTests { Map attr1 = new TreeMap(); Map attr2 = new LinkedHashMap(); Map> attr3 = - new HashMap>(); + new HashMap>(); attr0.put("foo", "bar"); attr1.put("bar", true); @@ -374,7 +373,7 @@ public class MappingCouchbaseConverterTests { ValueEntity readConverted = converter.read(ValueEntity.class, source); assertEquals(addy.emailAddr, readConverted.email.emailAddr); assertEquals(listOfEmails.get(0).emailAddr, - readConverted.listOfEmails.get(0).emailAddr); + readConverted.listOfEmails.get(0).emailAddr); } @Test @@ -486,6 +485,7 @@ public class MappingCouchbaseConverterTests { static class EntityWithoutID { private String attr0; + public EntityWithoutID(String a0) { attr0 = a0; } @@ -499,6 +499,7 @@ public class MappingCouchbaseConverterTests { static class StringEntity extends BaseEntity { private String attr0; + public StringEntity(String attr0) { this.attr0 = attr0; } @@ -506,6 +507,7 @@ public class MappingCouchbaseConverterTests { static class NumberEntity extends BaseEntity { private long attr0; + public NumberEntity(long attr0) { this.attr0 = attr0; } @@ -513,6 +515,7 @@ public class MappingCouchbaseConverterTests { static class BooleanEntity extends BaseEntity { private boolean attr0; + public BooleanEntity(boolean attr0) { this.attr0 = attr0; } @@ -523,6 +526,7 @@ public class MappingCouchbaseConverterTests { private int attr1; private double attr2; private boolean attr3; + public MixedSimpleEntity(String attr0, int attr1, double attr2, boolean attr3) { this.attr0 = attr0; this.attr1 = attr1; @@ -542,6 +546,7 @@ public class MappingCouchbaseConverterTests { private Map attr1; private Map attr2; private Map> attr3; + public MapEntity(Map attr0, Map attr1, Map attr2, Map> attr3) { this.attr0 = attr0; this.attr1 = attr1; @@ -554,6 +559,7 @@ public class MappingCouchbaseConverterTests { private List attr0; private List attr1; private List> attr2; + ListEntity(List attr0, List attr1, List> attr2) { this.attr0 = attr0; this.attr1 = attr1; @@ -565,6 +571,7 @@ public class MappingCouchbaseConverterTests { private Set attr0; private Set attr1; private Set> attr2; + SetEntity(Set attr0, Set attr1, Set> attr2) { this.attr0 = attr0; this.attr1 = attr1; @@ -584,6 +591,7 @@ public class MappingCouchbaseConverterTests { static class Email { private String emailAddr; + public Email(String emailAddr) { this.emailAddr = emailAddr; } @@ -615,6 +623,7 @@ public class MappingCouchbaseConverterTests { static class CustomObject { private BigDecimal weight; + public CustomObject(BigDecimal weight) { this.weight = weight; } diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListenerTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListenerTests.java index fee744e3..66facfaa 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListenerTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/event/AbstractCouchbaseEventListenerTests.java @@ -16,8 +16,11 @@ package org.springframework.data.couchbase.core.mapping.event; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.test.context.ContextConfiguration; @@ -25,8 +28,6 @@ import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; -import static org.junit.Assert.assertEquals; - /** * @author Michael Nitschinger */ @@ -49,9 +50,9 @@ public class AbstractCouchbaseEventListenerTests { couchbaseTemplate.save(new User("john smith", 18)); - assertEquals(beforeSave+1, eventListener.onBeforeSaveEvents.size()); - assertEquals(afterSave+1, eventListener.onAfterSaveEvents.size()); - assertEquals(beforeConvert+1, eventListener.onBeforeConvertEvents.size()); + assertEquals(beforeSave + 1, eventListener.onBeforeSaveEvents.size()); + assertEquals(afterSave + 1, eventListener.onAfterSaveEvents.size()); + assertEquals(beforeConvert + 1, eventListener.onBeforeConvertEvents.size()); } } diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/event/EventContextConfiguration.java b/src/test/java/org/springframework/data/couchbase/core/mapping/event/EventContextConfiguration.java index 6015046b..3803e2c5 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/event/EventContextConfiguration.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/event/EventContextConfiguration.java @@ -18,14 +18,14 @@ package org.springframework.data.couchbase.core.mapping.event; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.couchbase.TestApplicationConfig; +import org.springframework.data.couchbase.UnitTestApplicationConfig; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; /** * @author Michael Nitschinger */ @Configuration -public class EventContextConfiguration extends TestApplicationConfig { +public class EventContextConfiguration extends UnitTestApplicationConfig { @Bean public LocalValidatorFactoryBean validator() { diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/event/SimpleMappingEventListener.java b/src/test/java/org/springframework/data/couchbase/core/mapping/event/SimpleMappingEventListener.java index 9048f3ca..1e766301 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/event/SimpleMappingEventListener.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/event/SimpleMappingEventListener.java @@ -16,10 +16,10 @@ package org.springframework.data.couchbase.core.mapping.event; -import org.springframework.data.couchbase.core.mapping.CouchbaseDocument; - import java.util.ArrayList; +import org.springframework.data.couchbase.core.mapping.CouchbaseDocument; + /** * @author Michael Nitschinger */ diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/event/User.java b/src/test/java/org/springframework/data/couchbase/core/mapping/event/User.java index 597c7fa5..5f743b10 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/event/User.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/event/User.java @@ -16,11 +16,11 @@ package org.springframework.data.couchbase.core.mapping.event; -import org.springframework.data.annotation.Id; - import javax.validation.constraints.Min; import javax.validation.constraints.Size; +import org.springframework.data.annotation.Id; + /** * @author Michael Nitschinger */ diff --git a/src/test/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListenerTests.java b/src/test/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListenerTests.java index 05df2eea..0891400c 100644 --- a/src/test/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListenerTests.java +++ b/src/test/java/org/springframework/data/couchbase/core/mapping/event/ValidatingCouchbaseEventListenerTests.java @@ -16,19 +16,20 @@ package org.springframework.data.couchbase.core.mapping.event; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import javax.validation.ConstraintViolationException; + import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.validation.ConstraintViolationException; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - /** * @author Michael Nitschinger */ @@ -46,7 +47,8 @@ public class ValidatingCouchbaseEventListenerTests { try { template.save(user); fail(); - } catch (ConstraintViolationException e) { + } + catch (ConstraintViolationException e) { assertThat(e.getConstraintViolations().size(), equalTo(2)); } } diff --git a/src/test/resources/namespace/couchbase-bean.xml b/src/test/resources/configurations/couchbaseBucket-bean.xml similarity index 53% rename from src/test/resources/namespace/couchbase-bean.xml rename to src/test/resources/configurations/couchbaseBucket-bean.xml index 3b64b645..2c7e9e4d 100644 --- a/src/test/resources/namespace/couchbase-bean.xml +++ b/src/test/resources/configurations/couchbaseBucket-bean.xml @@ -2,20 +2,18 @@ - + - + - + - + - + - - + \ No newline at end of file diff --git a/src/test/resources/configurations/couchbaseCluster-bean.xml b/src/test/resources/configurations/couchbaseCluster-bean.xml new file mode 100644 index 00000000..2ad55028 --- /dev/null +++ b/src/test/resources/configurations/couchbaseCluster-bean.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + 192.1.2.3 + 192.4.5.6 + + + + 2.2.2.2 + 4.4.4.4 + + + \ No newline at end of file diff --git a/src/test/resources/configurations/couchbaseEnv-bean.xml b/src/test/resources/configurations/couchbaseEnv-bean.xml new file mode 100644 index 00000000..07fedf93 --- /dev/null +++ b/src/test/resources/configurations/couchbaseEnv-bean.xml @@ -0,0 +1,48 @@ + + + + + + + + + + \ No newline at end of file diff --git a/template.mf b/template.mf index 2111ab1d..654c5db7 100644 --- a/template.mf +++ b/template.mf @@ -8,7 +8,7 @@ Export-Template: org.springframework.data.couchbase.*;version="${project.version}" Import-Template: javax.enterprise.*;version="${cdi:[=.=.=,+1.0.0)}";resolution:=optional, - com.couchbase.client.*;version="${couchbase:[=.=.=,+1.0.0)}", + com.couchbase.client.*;version="${couchbase:[=.=.=,+2.2.0-dp)}", net.spy.memcached.*;version="[2.8.0,3.0.0)", com.fasterxml.jackson.*;version="${jackson:[=.=.=,+1.0.0)}", org.springframework.*;version="${spring:[=.=.=.=,+1.1.0)}", @@ -18,3 +18,4 @@ Import-Template: org.slf4j.*;version="${slf4j:[=.=.=,+1.0.0)}", org.joda.time.*;version="${jodatime:[=.=.=,+1.0.0)}";resolution:=optional, javax.validation.*;version="${validation:[=.=.=.=,+1.0.0)}";resolution:=optional +