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 694a35ba..2e0b4b36 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseOperations.java @@ -19,6 +19,8 @@ package org.springframework.data.couchbase.core; 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; @@ -41,6 +43,16 @@ public interface CouchbaseOperations { */ void save(Object objectToSave); + /** + * Save the given object. + *

+ *

When the document already exists (specified by its unique id), then it will be overriden. Otherwise it will be + * created.

+ * + * @param objectToSave the object to store in the bucket. + */ + void save(Object objectToSave, PersistTo persistTo, ReplicateTo replicateTo); + /** * Save a list of objects. *

@@ -51,15 +63,39 @@ public interface CouchbaseOperations { */ void save(Collection batchToSave); + /** + * Save a list of objects. + *

+ *

When one of the documents already exists (specified by its unique id), then it will be overriden. Otherwise it + * will be created.

+ * + * @param batchToSave the list of objects to store in the bucket. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void save(Collection batchToSave, PersistTo persistTo, ReplicateTo replicateTo); + /** * Insert the given object. *

*

When the document already exists (specified by its unique id), then it will not be overriden. Use the * {@link CouchbaseOperations#save} method for this task.

* - * @param objectToSave the object to add to the bucket. + * @param objectToInsert the object to add to the bucket. */ - void insert(Object objectToSave); + void insert(Object objectToInsert); + + /** + * Insert the given object. + *

+ *

When the document already exists (specified by its unique id), then it will not be overriden. Use the + * {@link CouchbaseOperations#save} method for this task.

+ * + * @param objectToInsert the object to add to the bucket. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void insert(Object objectToInsert, PersistTo persistTo, ReplicateTo replicateTo); /** * Insert a list of objects. @@ -67,9 +103,21 @@ public interface CouchbaseOperations { *

When one of the documents already exists (specified by its unique id), then it will not be overriden. Use the * {@link CouchbaseOperations#save} method for this.

* - * @param batchToSave the list of objects to add to the bucket. + * @param batchToInsert the list of objects to add to the bucket. */ - void insert(Collection batchToSave); + void insert(Collection batchToInsert); + + /** + * Insert a list of objects. + *

+ *

When one of the documents already exists (specified by its unique id), then it will not be overriden. Use the + * {@link CouchbaseOperations#save} method for this.

+ * + * @param batchToInsert the list of objects to add to the bucket. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void insert(Collection batchToInsert, PersistTo persistTo, ReplicateTo replicateTo); /** * Update the given object. @@ -77,9 +125,21 @@ public interface CouchbaseOperations { *

When the document does not exist (specified by its unique id) it will not be created. Use the * {@link CouchbaseOperations#save} method for this.

* - * @param objectToSave the object to add to the bucket. + * @param objectToUpdate the object to add to the bucket. */ - void update(Object objectToSave); + void update(Object objectToUpdate); + + /** + * Update the given object. + *

+ *

When the document does not exist (specified by its unique id) it will not be created. Use the + * {@link CouchbaseOperations#save} method for this.

+ * + * @param objectToUpdate the object to add to the bucket. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void update(Object objectToUpdate, PersistTo persistTo, ReplicateTo replicateTo); /** * Insert a list of objects. @@ -87,9 +147,21 @@ public interface CouchbaseOperations { *

If one of the documents does not exist (specified by its unique id), then it will not be created. Use the * {@link CouchbaseOperations#save} method for this.

* - * @param batchToSave the list of objects to add to the bucket. + * @param batchToUpdate the list of objects to add to the bucket. */ - void update(Collection batchToSave); + void update(Collection batchToUpdate); + + /** + * Insert a list of objects. + *

+ *

If one of the documents does not exist (specified by its unique id), then it will not be created. Use the + * {@link CouchbaseOperations#save} method for this.

+ * + * @param batchToUpdate the list of objects to add to the bucket. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void update(Collection batchToUpdate, PersistTo persistTo, ReplicateTo replicateTo); /** * Find an object by its given Id and map it to the corresponding entity. @@ -150,9 +222,21 @@ public interface CouchbaseOperations { * If the object is a String, it will be treated as the document key * directly. * - * @param object the Object to remove. + * @param objectToRemove the Object to remove. */ - void remove(Object object); + void remove(Object objectToRemove); + + /** + * Remove the given object from the bucket by id. + *

+ * If the object is a String, it will be treated as the document key + * directly. + * + * @param objectToRemove the Object to remove. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void remove(Object objectToRemove, PersistTo persistTo, ReplicateTo replicateTo); /** * Remove a list of objects from the bucket by id. @@ -161,6 +245,15 @@ public interface CouchbaseOperations { */ void remove(Collection batchToRemove); + /** + * Remove a list of objects from the bucket by id. + * + * @param batchToRemove the list of Objects to remove. + * @param persistTo the persistence constraint setting. + * @param replicateTo the replication constraint setting. + */ + void remove(Collection batchToRemove, PersistTo persistTo, ReplicateTo replicateTo); + /** * Executes a BucketCallback translating any exceptions as necessary. *

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 0d6a0520..2828a2ef 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseTemplate.java @@ -21,6 +21,8 @@ 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.PersistTo; +import net.spy.memcached.ReplicateTo; import net.spy.memcached.internal.OperationFuture; import org.springframework.dao.QueryTimeoutException; import org.springframework.data.couchbase.core.convert.CouchbaseConverter; @@ -49,7 +51,7 @@ import java.util.concurrent.TimeoutException; */ public class CouchbaseTemplate implements CouchbaseOperations { - private CouchbaseClient client; + private final CouchbaseClient client; private CouchbaseConverter couchbaseConverter; protected final MappingContext, CouchbasePersistentProperty> mappingContext; private static final Collection ITERABLE_CLASSES; @@ -77,18 +79,18 @@ public class CouchbaseTemplate implements CouchbaseOperations { public CouchbaseTemplate(final CouchbaseClient client, final TranslationService translationService) { this.client = client; - this.couchbaseConverter = couchbaseConverter == null ? getDefaultConverter() : couchbaseConverter; + couchbaseConverter = couchbaseConverter == null ? getDefaultConverter() : couchbaseConverter; this.translationService = translationService == null ? getDefaultTranslationService() : translationService; - mappingContext = this.couchbaseConverter.getMappingContext(); + mappingContext = couchbaseConverter.getMappingContext(); } - private CouchbaseConverter getDefaultConverter() { + private static CouchbaseConverter getDefaultConverter() { final MappingCouchbaseConverter converter = new MappingCouchbaseConverter(new CouchbaseMappingContext()); converter.afterPropertiesSet(); return converter; } - private TranslationService getDefaultTranslationService() { + private static TranslationService getDefaultTranslationService() { final JacksonTranslationService jacksonTranslationService = new JacksonTranslationService(); jacksonTranslationService.afterPropertiesSet(); return jacksonTranslationService; @@ -102,67 +104,43 @@ public class CouchbaseTemplate implements CouchbaseOperations { return translationService.decode(source, target); } - public final void insert(final Object objectToSave) { - ensureNotIterable(objectToSave); - - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToSave, converted); - - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - return client.add(converted.getId(), converted.getExpiration(), translateEncode(converted)).get(); - } - }); + @Override + public final void insert(final Object objectToInsert) { + insert(objectToInsert, PersistTo.ZERO, ReplicateTo.ZERO); } - public final void insert(final Collection batchToSave) { - for (final Object aBatchToSave : batchToSave) { - insert(aBatchToSave); + @Override + public final void insert(final Collection batchToInsert) { + for (final Object toInsert : batchToInsert) { + insert(toInsert); } } + @Override public void save(final Object objectToSave) { - ensureNotIterable(objectToSave); - - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToSave, converted); - - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - return client.set(converted.getId(), converted.getExpiration(), translateEncode(converted)).get(); - } - }); + save(objectToSave, PersistTo.ZERO, ReplicateTo.ZERO); } + @Override public void save(final Collection batchToSave) { - for (final Object aBatchToSave : batchToSave) { - save(aBatchToSave); + for (final Object toSave : batchToSave) { + save(toSave); } } - public void update(final Object objectToSave) { - ensureNotIterable(objectToSave); - - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToSave, converted); - - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - return client.replace(converted.getId(), converted.getExpiration(), translateEncode(converted)).get(); - } - }); - + @Override + public void update(final Object objectToUpdate) { + update(objectToUpdate, PersistTo.ZERO, ReplicateTo.ZERO); } - public void update(final Collection batchToSave) { - for (final Object aBatchToSave : batchToSave) { - update(aBatchToSave); + @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) { String result = execute(new BucketCallback() { @Override @@ -212,33 +190,15 @@ public class CouchbaseTemplate implements CouchbaseOperations { }); } + @Override public void remove(final Object objectToRemove) { - ensureNotIterable(objectToRemove); - - if (objectToRemove instanceof String) { - execute(new BucketCallback() { - @Override - public Boolean doInBucket() throws InterruptedException, ExecutionException { - return client.delete((String) objectToRemove).get(); - } - }); - return; - } - - final CouchbaseDocument converted = new CouchbaseDocument(); - couchbaseConverter.write(objectToRemove, converted); - - execute(new BucketCallback>() { - @Override - public OperationFuture doInBucket() { - return client.delete(converted.getId()); - } - }); + remove(objectToRemove, PersistTo.ZERO, ReplicateTo.ZERO); } + @Override public void remove(final Collection batchToRemove) { - for (final Object aBatchToRemove : batchToRemove) { - remove(aBatchToRemove); + for (final Object toRemove : batchToRemove) { + remove(toRemove); } } @@ -273,7 +233,7 @@ public class CouchbaseTemplate implements CouchbaseOperations { * * @param o the object to verify. */ - protected final void ensureNotIterable(Object o) { + protected static void ensureNotIterable(Object o) { if (null != o) { if (o.getClass().isArray() || ITERABLE_CLASSES.contains(o.getClass().getName())) { throw new IllegalArgumentException("Cannot use a collection here."); @@ -285,4 +245,105 @@ public class CouchbaseTemplate implements CouchbaseOperations { public CouchbaseConverter getConverter() { return couchbaseConverter; } + + @Override + public void save(Object objectToSave, final PersistTo persistTo, final ReplicateTo replicateTo) { + ensureNotIterable(objectToSave); + + final CouchbaseDocument converted = new CouchbaseDocument(); + couchbaseConverter.write(objectToSave, converted); + + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + return client.set(converted.getId(), converted.getExpiration(), translateEncode(converted), persistTo, + replicateTo).get(); + } + }); + } + + @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 CouchbaseDocument converted = new CouchbaseDocument(); + couchbaseConverter.write(objectToInsert, converted); + + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + return client.add(converted.getId(), converted.getExpiration(), translateEncode(converted), persistTo, + replicateTo).get(); + } + }); + } + + @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 CouchbaseDocument converted = new CouchbaseDocument(); + couchbaseConverter.write(objectToUpdate, converted); + + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + return client.replace(converted.getId(), converted.getExpiration(), translateEncode(converted), persistTo, + replicateTo).get(); + } + }); + } + + @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); + + if (objectToRemove instanceof String) { + execute(new BucketCallback() { + @Override + public Boolean doInBucket() throws InterruptedException, ExecutionException { + return client.delete((String) objectToRemove, persistTo, replicateTo).get(); + } + }); + return; + } + + final CouchbaseDocument converted = new CouchbaseDocument(); + couchbaseConverter.write(objectToRemove, converted); + + execute(new BucketCallback>() { + @Override + public OperationFuture doInBucket() { + return client.delete(converted.getId()); + } + }); + } + + @Override + public void remove(Collection batchToRemove, PersistTo persistTo, ReplicateTo replicateTo) { + for (Object toRemove : batchToRemove) { + remove(toRemove, persistTo, replicateTo); + } + } } diff --git a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java b/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java index 3a4377ff..b6c28330 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java +++ b/src/test/java/org/springframework/data/couchbase/repository/SimpleCouchbaseRepositoryListener.java @@ -19,6 +19,8 @@ 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 org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; @@ -40,13 +42,15 @@ public class SimpleCouchbaseRepositoryListener extends DependencyInjectionTestEx for (int i = 0; i < 100; i++) { User u = new User("testuser-" + i, "uname-" + i); - template.save(u); + template.save(u, PersistTo.MASTER, ReplicateTo.ZERO); } + } private void createAndWaitForDesignDocs(CouchbaseClient client) { DesignDocument designDoc = new DesignDocument("user"); - String mapFunction = "function (doc, meta) { if(doc._class == \"org.springframework.data.couchbase.repository.User\") { emit(null, null); } }"; + 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); }