Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.couchbase.client.java.CouchbaseAsyncBucket Maven / Gradle / Ivy
/*
* Copyright (c) 2016 Couchbase, Inc.
*
* 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 com.couchbase.client.java;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.core.ClusterFacade;
import com.couchbase.client.core.CouchbaseException;
import com.couchbase.client.core.lang.Tuple2;
import com.couchbase.client.core.logging.CouchbaseLogger;
import com.couchbase.client.core.logging.CouchbaseLoggerFactory;
import com.couchbase.client.core.message.ResponseStatus;
import com.couchbase.client.core.message.cluster.CloseBucketRequest;
import com.couchbase.client.core.message.cluster.CloseBucketResponse;
import com.couchbase.client.core.message.kv.AppendRequest;
import com.couchbase.client.core.message.kv.AppendResponse;
import com.couchbase.client.core.message.kv.CounterRequest;
import com.couchbase.client.core.message.kv.CounterResponse;
import com.couchbase.client.core.message.kv.GetRequest;
import com.couchbase.client.core.message.kv.GetResponse;
import com.couchbase.client.core.message.kv.InsertRequest;
import com.couchbase.client.core.message.kv.InsertResponse;
import com.couchbase.client.core.message.kv.ObserveRequest;
import com.couchbase.client.core.message.kv.ObserveResponse;
import com.couchbase.client.core.message.kv.PrependRequest;
import com.couchbase.client.core.message.kv.PrependResponse;
import com.couchbase.client.core.message.kv.RemoveRequest;
import com.couchbase.client.core.message.kv.RemoveResponse;
import com.couchbase.client.core.message.kv.ReplaceRequest;
import com.couchbase.client.core.message.kv.ReplaceResponse;
import com.couchbase.client.core.message.kv.TouchRequest;
import com.couchbase.client.core.message.kv.TouchResponse;
import com.couchbase.client.core.message.kv.UnlockRequest;
import com.couchbase.client.core.message.kv.UnlockResponse;
import com.couchbase.client.core.message.kv.UpsertRequest;
import com.couchbase.client.core.message.kv.UpsertResponse;
import com.couchbase.client.core.message.observe.Observe;
import com.couchbase.client.core.message.search.SearchQueryRequest;
import com.couchbase.client.core.message.search.SearchQueryResponse;
import com.couchbase.client.core.message.view.ViewQueryRequest;
import com.couchbase.client.core.message.view.ViewQueryResponse;
import com.couchbase.client.deps.io.netty.buffer.ByteBuf;
import com.couchbase.client.java.bucket.AsyncBucketManager;
import com.couchbase.client.java.bucket.DefaultAsyncBucketManager;
import com.couchbase.client.java.bucket.ReplicaReader;
import com.couchbase.client.java.document.Document;
import com.couchbase.client.java.document.JsonDocument;
import com.couchbase.client.java.document.JsonLongDocument;
import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.error.CASMismatchException;
import com.couchbase.client.java.error.CouchbaseOutOfMemoryException;
import com.couchbase.client.java.error.DocumentAlreadyExistsException;
import com.couchbase.client.java.error.DocumentDoesNotExistException;
import com.couchbase.client.java.error.DurabilityException;
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.query.AsyncN1qlQueryResult;
import com.couchbase.client.java.query.N1qlQuery;
import com.couchbase.client.java.query.Statement;
import com.couchbase.client.java.query.core.N1qlQueryExecutor;
import com.couchbase.client.java.repository.AsyncRepository;
import com.couchbase.client.java.repository.CouchbaseAsyncRepository;
import com.couchbase.client.java.search.SearchQuery;
import com.couchbase.client.java.search.queries.AbstractFtsQuery;
import com.couchbase.client.java.search.result.AsyncSearchQueryResult;
import com.couchbase.client.java.search.result.impl.DefaultAsyncSearchQueryResult;
import com.couchbase.client.java.subdoc.AsyncLookupInBuilder;
import com.couchbase.client.java.subdoc.AsyncMutateInBuilder;
import com.couchbase.client.java.transcoder.BinaryTranscoder;
import com.couchbase.client.java.transcoder.JacksonTransformers;
import com.couchbase.client.java.transcoder.JsonArrayTranscoder;
import com.couchbase.client.java.transcoder.JsonBooleanTranscoder;
import com.couchbase.client.java.transcoder.JsonDoubleTranscoder;
import com.couchbase.client.java.transcoder.JsonLongTranscoder;
import com.couchbase.client.java.transcoder.JsonStringTranscoder;
import com.couchbase.client.java.transcoder.JsonTranscoder;
import com.couchbase.client.java.transcoder.LegacyTranscoder;
import com.couchbase.client.java.transcoder.RawJsonTranscoder;
import com.couchbase.client.java.transcoder.SerializableTranscoder;
import com.couchbase.client.java.transcoder.StringTranscoder;
import com.couchbase.client.java.transcoder.Transcoder;
import com.couchbase.client.java.transcoder.subdoc.FragmentTranscoder;
import com.couchbase.client.java.transcoder.subdoc.JacksonFragmentTranscoder;
import com.couchbase.client.java.view.AsyncSpatialViewResult;
import com.couchbase.client.java.view.AsyncViewResult;
import com.couchbase.client.java.view.SpatialViewQuery;
import com.couchbase.client.java.view.ViewQuery;
import com.couchbase.client.java.view.ViewQueryResponseMapper;
import com.couchbase.client.java.view.ViewRetryHandler;
import rx.Observable;
import rx.functions.Func0;
import rx.functions.Func1;
public class CouchbaseAsyncBucket implements AsyncBucket {
private static final CouchbaseLogger LOGGER = CouchbaseLoggerFactory.getInstance(CouchbaseAsyncBucket.class);
private static final int COUNTER_NOT_EXISTS_EXPIRY = 0xffffffff;
public static final String CURRENT_BUCKET_IDENTIFIER = "#CURRENT_BUCKET#";
public static final JsonTranscoder JSON_OBJECT_TRANSCODER = new JsonTranscoder();
public static final JsonArrayTranscoder JSON_ARRAY_TRANSCODER = new JsonArrayTranscoder();
public static final JsonBooleanTranscoder JSON_BOOLEAN_TRANSCODER = new JsonBooleanTranscoder();
public static final JsonDoubleTranscoder JSON_DOUBLE_TRANSCODER = new JsonDoubleTranscoder();
public static final JsonLongTranscoder JSON_LONG_TRANSCODER = new JsonLongTranscoder();
public static final JsonStringTranscoder JSON_STRING_TRANSCODER = new JsonStringTranscoder();
public static final RawJsonTranscoder RAW_JSON_TRANSCODER = new RawJsonTranscoder();
public static final LegacyTranscoder LEGACY_TRANSCODER = new LegacyTranscoder();
public static final BinaryTranscoder BINARY_TRANSCODER = new BinaryTranscoder();
public static final StringTranscoder STRING_TRANSCODER = new StringTranscoder();
public static final SerializableTranscoder SERIALIZABLE_TRANSCODER = new SerializableTranscoder();
private final String bucket;
private final String password;
private final ClusterFacade core;
private final Map, Transcoder extends Document, ?>> transcoders;
//TODO this could be opened for customization like with transcoders
private final FragmentTranscoder subdocumentTranscoder = new JacksonFragmentTranscoder(JacksonTransformers.MAPPER);
private final AsyncBucketManager bucketManager;
private final CouchbaseEnvironment environment;
/** the bucket's {@link N1qlQueryExecutor}. Prefer using {@link #n1qlQueryExecutor()} since it allows mocking and testing */
private final N1qlQueryExecutor n1qlQueryExecutor;
private volatile boolean closed;
public CouchbaseAsyncBucket(final ClusterFacade core, final CouchbaseEnvironment environment, final String name,
final String password, final List> customTranscoders) {
bucket = name;
this.password = password;
this.core = core;
this.environment = environment;
this.closed = false;
transcoders = new ConcurrentHashMap, Transcoder extends Document, ?>>();
transcoders.put(JSON_OBJECT_TRANSCODER.documentType(), JSON_OBJECT_TRANSCODER);
transcoders.put(JSON_ARRAY_TRANSCODER.documentType(), JSON_ARRAY_TRANSCODER);
transcoders.put(JSON_BOOLEAN_TRANSCODER.documentType(), JSON_BOOLEAN_TRANSCODER);
transcoders.put(JSON_DOUBLE_TRANSCODER.documentType(), JSON_DOUBLE_TRANSCODER);
transcoders.put(JSON_LONG_TRANSCODER.documentType(), JSON_LONG_TRANSCODER);
transcoders.put(JSON_STRING_TRANSCODER.documentType(), JSON_STRING_TRANSCODER);
transcoders.put(RAW_JSON_TRANSCODER.documentType(), RAW_JSON_TRANSCODER);
transcoders.put(LEGACY_TRANSCODER.documentType(), LEGACY_TRANSCODER);
transcoders.put(BINARY_TRANSCODER.documentType(), BINARY_TRANSCODER);
transcoders.put(STRING_TRANSCODER.documentType(), STRING_TRANSCODER);
transcoders.put(SERIALIZABLE_TRANSCODER.documentType(), SERIALIZABLE_TRANSCODER);
for (Transcoder extends Document, ?> custom : customTranscoders) {
transcoders.put(custom.documentType(), custom);
}
bucketManager = DefaultAsyncBucketManager.create(bucket, password, core);
boolean n1qlPreparedEncodedPlanEnabled = "true".equalsIgnoreCase(System.getProperty(N1qlQueryExecutor.ENCODED_PLAN_ENABLED_PROPERTY, "true")); //active by default
n1qlQueryExecutor = new N1qlQueryExecutor(core, bucket, password, n1qlPreparedEncodedPlanEnabled);
}
@Override
public String name() {
return bucket;
}
@Override
public Observable core() {
return Observable.just(core);
}
@Override
public FragmentTranscoder subdocumentTranscoder() {
return subdocumentTranscoder;
}
/**
* Returns the underlying {@link N1qlQueryExecutor} used to perform N1QL queries.
*
* Handle with care since all additional checks that are normally performed by this library may be skipped (hence
* the protected visibility).
*/
protected N1qlQueryExecutor n1qlQueryExecutor() {
return this.n1qlQueryExecutor;
}
@Override
public CouchbaseEnvironment environment() {
return environment;
}
@Override
public Observable repository() {
return Observable.just((AsyncRepository) new CouchbaseAsyncRepository(this));
}
@Override
public Observable get(final String id) {
return get(id, JsonDocument.class);
}
@Override
@SuppressWarnings("unchecked")
public > Observable get(D document) {
return (Observable) get(document.id(), document.getClass());
}
@Override
@SuppressWarnings("unchecked")
public > Observable get(final String id, final Class target) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new GetRequest(id, bucket));
}
})
.filter(new Func1() {
@Override
public Boolean call(GetResponse response) {
if (response.status().isSuccess()) {
return true;
}
ByteBuf content = response.content();
if (content != null && content.refCnt() > 0) {
content.release();
}
switch(response.status()) {
case NOT_EXISTS:
return false;
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
})
.map(new Func1() {
@Override
public D call(final GetResponse response) {
Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(target);
return (D) transcoder.decode(id, response.content(), response.cas(), 0, response.flags(),
response.status());
}
});
}
@Override
public Observable exists(final String id) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new ObserveRequest(id, 0, true, (short) 0, bucket));
}
})
.map(new Func1() {
@Override
public Boolean call(ObserveResponse response) {
ByteBuf content = response.content();
if (content != null && content.refCnt() > 0) {
content.release();
}
ObserveResponse.ObserveStatus foundStatus = response.observeStatus();
if (foundStatus == ObserveResponse.ObserveStatus.FOUND_PERSISTED
|| foundStatus == ObserveResponse.ObserveStatus.FOUND_NOT_PERSISTED) {
return true;
}
return false;
}
});
}
@Override
public > Observable exists(D document) {
return exists(document.id());
}
@Override
public Observable getAndLock(String id, int lockTime) {
return getAndLock(id, lockTime, JsonDocument.class);
}
@Override
@SuppressWarnings("unchecked")
public > Observable getAndLock(D document, int lockTime) {
return (Observable) getAndLock(document.id(), lockTime, document.getClass());
}
@Override
@SuppressWarnings("unchecked")
public > Observable getAndLock(final String id, final int lockTime, final Class target) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new GetRequest(id, bucket, true, false, lockTime));
}
})
.filter(new Func1() {
@Override
public Boolean call(GetResponse response) {
if (response.status().isSuccess()) {
return true;
}
ByteBuf content = response.content();
if (content != null && content.refCnt() > 0) {
content.release();
}
switch (response.status()) {
case NOT_EXISTS:
return false;
case TEMPORARY_FAILURE:
throw new TemporaryLockFailureException();
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
})
.map(new Func1() {
@Override
public D call(final GetResponse response) {
Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(target);
return (D) transcoder.decode(id, response.content(), response.cas(), 0, response.flags(),
response.status());
}
});
}
@Override
public Observable getAndTouch(String id, int expiry) {
return getAndTouch(id, expiry, JsonDocument.class);
}
@Override
@SuppressWarnings("unchecked")
public > Observable getAndTouch(D document) {
return (Observable) getAndTouch(document.id(), document.expiry(), document.getClass());
}
@Override
@SuppressWarnings("unchecked")
public > Observable getAndTouch(final String id, final int expiry, final Class target) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new GetRequest(id, bucket, false, true, expiry));
}
})
.filter(new Func1() {
@Override
public Boolean call(GetResponse response) {
if (response.status().isSuccess()) {
return true;
}
ByteBuf content = response.content();
if (content != null && content.refCnt() > 0) {
content.release();
}
switch (response.status()) {
case NOT_EXISTS:
return false;
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
})
.map(new Func1() {
@Override
public D call(final GetResponse response) {
Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(target);
return (D) transcoder.decode(id, response.content(), response.cas(), 0, response.flags(),
response.status());
}
});
}
@Override
public Observable getFromReplica(final String id, final ReplicaMode type) {
return getFromReplica(id, type, JsonDocument.class);
}
@Override
@SuppressWarnings("unchecked")
public > Observable getFromReplica(final D document, final ReplicaMode type) {
return (Observable) getFromReplica(document.id(), type, document.getClass());
}
@Override
@SuppressWarnings("unchecked")
public > Observable getFromReplica(final String id, final ReplicaMode type,
final Class target) {
return ReplicaReader
.read(core, id, type, bucket)
.map(new Func1() {
@Override
public D call(final GetResponse response) {
Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(target);
return (D) transcoder.decode(id, response.content(), response.cas(), 0, response.flags(),
response.status());
}
})
.cache(type.maxAffectedNodes());
}
@Override
@SuppressWarnings("unchecked")
public > Observable insert(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
Tuple2 encoded = transcoder.encode((Document) document);
return core.send(new InsertRequest(document.id(), encoded.value1(), document.expiry(), encoded.value2(), bucket));
}
}).map(new Func1() {
@Override
public D call(InsertResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), document.expiry(),
document.content(), response.cas(), response.mutationToken());
}
switch (response.status()) {
case TOO_BIG:
throw new RequestTooBigException();
case EXISTS:
throw new DocumentAlreadyExistsException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public > Observable insert(final D document, final PersistTo persistTo,
final ReplicateTo replicateTo) {
Observable insertResult = insert(document);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return insertResult;
}
return insertResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(), persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
}).onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
@SuppressWarnings("unchecked")
public > Observable upsert(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
Tuple2 encoded = transcoder.encode((Document) document);
return core.send(new UpsertRequest(document.id(), encoded.value1(), document.expiry(), encoded.value2(), bucket));
}
}).map(new Func1() {
@Override
public D call(UpsertResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), document.expiry(),
document.content(), response.cas(), response.mutationToken());
}
switch (response.status()) {
case TOO_BIG:
throw new RequestTooBigException();
case EXISTS:
throw new CASMismatchException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public > Observable upsert(final D document, final PersistTo persistTo,
final ReplicateTo replicateTo) {
Observable upsertResult = upsert(document);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return upsertResult;
}
return upsertResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(), persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
})
.onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
@SuppressWarnings("unchecked")
public > Observable replace(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
Tuple2 encoded = transcoder.encode((Document) document);
return core.send(new ReplaceRequest(document.id(), encoded.value1(), document.cas(), document.expiry(), encoded.value2(), bucket));
}
}).map(new Func1() {
@Override
public D call(ReplaceResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), document.expiry(),
document.content(), response.cas(), response.mutationToken());
}
switch (response.status()) {
case TOO_BIG:
throw new RequestTooBigException();
case NOT_EXISTS:
throw new DocumentDoesNotExistException();
case EXISTS:
throw new CASMismatchException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public > Observable replace(final D document, final PersistTo persistTo,
final ReplicateTo replicateTo) {
Observable replaceResult = replace(document);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return replaceResult;
}
return replaceResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(), persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
}).onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
@SuppressWarnings("unchecked")
public > Observable remove(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new RemoveRequest(document.id(), document.cas(), bucket));
}
}).map(new Func1() {
@Override
public D call(final RemoveResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), 0, null, response.cas(), response.mutationToken());
}
switch (response.status()) {
case NOT_EXISTS:
throw new DocumentDoesNotExistException();
case EXISTS:
throw new CASMismatchException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public Observable remove(final String id) {
return remove(id, JsonDocument.class);
}
@Override
@SuppressWarnings("unchecked")
public > Observable remove(final String id, final Class target) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(target);
return remove((D) transcoder.newDocument(id, 0, null, 0));
}
@Override
@SuppressWarnings("unchecked")
public > Observable remove(D document, final PersistTo persistTo, final ReplicateTo replicateTo) {
return observeRemove(remove(document), persistTo, replicateTo);
}
@Override
public Observable remove(String id, PersistTo persistTo, ReplicateTo replicateTo) {
return remove(id, persistTo, replicateTo, JsonDocument.class);
}
@Override
public > Observable remove(String id, final PersistTo persistTo,
final ReplicateTo replicateTo, Class target) {
return observeRemove(remove(id, target), persistTo, replicateTo);
}
/**
* Helper method to observe the result of a remove operation with the given durability
* requirements.
*
* @param removeResult the original result of the actual remove operation.
* @param persistTo the persistence requirement given.
* @param replicateTo the replication requirement given.
* @return an observable reporting success or error of the observe operation.
*/
private > Observable observeRemove(Observable removeResult,
final PersistTo persistTo, final ReplicateTo replicateTo) {
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return removeResult;
}
return removeResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), true, doc.mutationToken(),
persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
}).onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
public Observable query(final ViewQuery query) {
Observable source = Observable.defer(new Func0>() {
@Override
public Observable call() {
final ViewQueryRequest request = new ViewQueryRequest(query.getDesign(), query.getView(),
query.isDevelopment(), query.toQueryString(), query.getKeys(), bucket, password);
return core.send(request);
}
});
return ViewRetryHandler
.retryOnCondition(source)
.flatMap(new Func1>() {
@Override
public Observable call(final ViewQueryResponse response) {
return ViewQueryResponseMapper.mapToViewResult(CouchbaseAsyncBucket.this, query, response);
}
});
}
@Override
public Observable query(final SearchQuery query) {
final String indexName = query.indexName();
final AbstractFtsQuery queryPart = query.query();
//always set a server side timeout. if not explicit, set it to the client side timeout
if (query.getServerSideTimeout() == null) {
query.serverSideTimeout(environment().searchTimeout(), TimeUnit.MILLISECONDS);
}
Observable source = Observable.defer(new Func0>() {
@Override
public Observable call() {
final SearchQueryRequest request =
new SearchQueryRequest(indexName, query.export().toString(), bucket, password);
return core.send(request);
}
});
return source.map(new Func1() {
@Override
public AsyncSearchQueryResult call(SearchQueryResponse response) {
if (response.status().isSuccess()) {
JsonObject json = JsonObject.fromJson(response.payload());
return DefaultAsyncSearchQueryResult.fromJson(json);
} else if (response.status() == ResponseStatus.INVALID_ARGUMENTS) {
return DefaultAsyncSearchQueryResult.fromHttp400(response.payload());
} else {
throw new CouchbaseException("Could not query search index, " + response.status() + ": " + response.payload());
}
}
});
}
@Override
public Observable query(final SpatialViewQuery query) {
Observable source = Observable.defer(new Func0>() {
@Override
public Observable call() {
final ViewQueryRequest request = new ViewQueryRequest(query.getDesign(), query.getView(),
query.isDevelopment(), true, query.toString(), null, bucket, password);
return core.send(request);
}
});
return ViewRetryHandler
.retryOnCondition(source)
.flatMap(new Func1>() {
@Override
public Observable call(final ViewQueryResponse response) {
return ViewQueryResponseMapper.mapToSpatialViewResult(CouchbaseAsyncBucket.this, query, response);
}
});
}
@Override
public Observable query(final Statement statement) {
return query(N1qlQuery.simple(statement));
}
@Override
public Observable query(final N1qlQuery query) {
if (!query.params().hasServerSideTimeout()) {
query.params().serverSideTimeout(environment().queryTimeout(), TimeUnit.MILLISECONDS);
}
return n1qlQueryExecutor.execute(query);
}
@Override
public Observable counter(String id, long delta) {
return counter(id, delta, 0, COUNTER_NOT_EXISTS_EXPIRY);
}
@Override
public Observable counter(String id, long delta, long initial) {
return counter(id, delta, initial, 0);
}
@Override
public Observable counter(final String id, final long delta, final long initial, final int expiry) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new CounterRequest(id, initial, delta, expiry, bucket));
}
}).map(new Func1() {
@Override
public JsonLongDocument call(CounterResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
int returnedExpiry = expiry == COUNTER_NOT_EXISTS_EXPIRY ? 0 : expiry;
return JsonLongDocument.create(id, returnedExpiry, response.value(),
response.cas(), response.mutationToken());
}
switch (response.status()) {
case NOT_EXISTS:
throw new DocumentDoesNotExistException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public Observable unlock(final String id, final long cas) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new UnlockRequest(id, cas, bucket));
}
}).map(new Func1() {
@Override
public Boolean call(UnlockResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return true;
}
switch (response.status()) {
case NOT_EXISTS:
throw new DocumentDoesNotExistException();
case TEMPORARY_FAILURE:
throw new TemporaryLockFailureException();
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public > Observable unlock(D document) {
return unlock(document.id(), document.cas());
}
@Override
public Observable touch(final String id, final int expiry) {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new TouchRequest(id, expiry, bucket));
}
}).map(new Func1() {
@Override
public Boolean call(TouchResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return true;
}
switch (response.status()) {
case NOT_EXISTS:
throw new DocumentDoesNotExistException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public > Observable touch(D document) {
return touch(document.id(), document.expiry());
}
@Override
@SuppressWarnings("unchecked")
public > Observable append(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
Tuple2 encoded = transcoder.encode((Document) document);
return core.send(new AppendRequest(document.id(), document.cas(), encoded.value1(), bucket));
}
}).map(new Func1() {
@Override
public D call(final AppendResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), 0, null, response.cas(), response.mutationToken());
}
switch (response.status()) {
case TOO_BIG:
throw new RequestTooBigException();
case NOT_STORED:
throw new DocumentDoesNotExistException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
case EXISTS:
throw new CASMismatchException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
@SuppressWarnings("unchecked")
public > Observable prepend(final D document) {
final Transcoder, Object> transcoder = (Transcoder, Object>) transcoders.get(document.getClass());
return Observable.defer(new Func0>() {
@Override
public Observable call() {
Tuple2 encoded = transcoder.encode((Document) document);
return core.send(new PrependRequest(document.id(), document.cas(), encoded.value1(), bucket));
}
}).map(new Func1() {
@Override
public D call(final PrependResponse response) {
if (response.content() != null && response.content().refCnt() > 0) {
response.content().release();
}
if (response.status().isSuccess()) {
return (D) transcoder.newDocument(document.id(), 0, null, response.cas(), response.mutationToken());
}
switch (response.status()) {
case TOO_BIG:
throw new RequestTooBigException();
case NOT_STORED:
throw new DocumentDoesNotExistException();
case TEMPORARY_FAILURE:
case SERVER_BUSY:
throw new TemporaryFailureException();
case OUT_OF_MEMORY:
throw new CouchbaseOutOfMemoryException();
case EXISTS:
throw new CASMismatchException();
default:
throw new CouchbaseException(response.status().toString());
}
}
});
}
@Override
public Observable bucketManager() {
return Observable.just(bucketManager);
}
@Override
public > Observable insert(D document, PersistTo persistTo) {
return insert(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable insert(D document, ReplicateTo replicateTo) {
return insert(document, PersistTo.NONE, replicateTo);
}
@Override
public > Observable upsert(D document, PersistTo persistTo) {
return upsert(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable upsert(D document, ReplicateTo replicateTo) {
return upsert(document, PersistTo.NONE, replicateTo);
}
@Override
public > Observable replace(D document, PersistTo persistTo) {
return replace(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable replace(D document, ReplicateTo replicateTo) {
return replace(document, PersistTo.NONE, replicateTo);
}
@Override
public > Observable remove(D document, PersistTo persistTo) {
return remove(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable remove(D document, ReplicateTo replicateTo) {
return remove(document, PersistTo.NONE, replicateTo);
}
@Override
public Observable remove(String id, PersistTo persistTo) {
return remove(id, persistTo, ReplicateTo.NONE);
}
@Override
public Observable remove(String id, ReplicateTo replicateTo) {
return remove(id, PersistTo.NONE, replicateTo);
}
@Override
public > Observable remove(String id, PersistTo persistTo, Class target) {
return remove(id, persistTo, ReplicateTo.NONE, target);
}
@Override
public > Observable remove(String id, ReplicateTo replicateTo, Class target) {
return remove(id, PersistTo.NONE, replicateTo, target);
}
@Override
public Observable counter(String id, long delta, PersistTo persistTo) {
return counter(id, delta, persistTo, ReplicateTo.NONE);
}
@Override
public Observable counter(String id, long delta, ReplicateTo replicateTo) {
return counter(id, delta, PersistTo.NONE, replicateTo);
}
@Override
public Observable counter(String id, long delta, long initial, PersistTo persistTo) {
return counter(id, delta, initial, persistTo, ReplicateTo.NONE);
}
@Override
public Observable counter(String id, long delta, long initial, ReplicateTo replicateTo) {
return counter(id, delta, initial, PersistTo.NONE, replicateTo);
}
@Override
public Observable counter(String id, long delta, long initial, int expiry, PersistTo persistTo) {
return counter(id, delta, initial, expiry, persistTo, ReplicateTo.NONE);
}
@Override
public Observable counter(String id, long delta, long initial, int expiry, ReplicateTo replicateTo) {
return counter(id, delta, initial, expiry, PersistTo.NONE, replicateTo);
}
@Override
public Observable counter(String id, long delta, long initial, PersistTo persistTo, ReplicateTo replicateTo) {
return counter(id, delta, initial, 0, persistTo, replicateTo);
}
@Override
public Observable counter(String id, long delta, PersistTo persistTo, ReplicateTo replicateTo) {
return counter(id, delta, 0, COUNTER_NOT_EXISTS_EXPIRY, persistTo, replicateTo);
}
@Override
public Observable counter(String id, long delta, long initial, int expiry, final PersistTo persistTo, final ReplicateTo replicateTo) {
Observable counterResult = counter(id, delta, initial, expiry);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return counterResult;
}
return counterResult.flatMap(new Func1>() {
@Override
public Observable call(final JsonLongDocument doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(),
persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public JsonLongDocument call(Boolean aBoolean) {
return doc;
}
})
.onErrorResumeNext(new Func1>() {
@Override
public Observable extends JsonLongDocument> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
public > Observable append(D document, PersistTo persistTo) {
return append(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable append(D document, ReplicateTo replicateTo) {
return append(document, PersistTo.NONE, replicateTo);
}
@Override
public > Observable append(D document, final PersistTo persistTo, final ReplicateTo replicateTo) {
Observable appendResult = append(document);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return appendResult;
}
return appendResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(), persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
}).onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
@Override
public > Observable prepend(D document, PersistTo persistTo) {
return prepend(document, persistTo, ReplicateTo.NONE);
}
@Override
public > Observable prepend(D document, ReplicateTo replicateTo) {
return prepend(document, PersistTo.NONE, replicateTo);
}
@Override
public > Observable prepend(D document, final PersistTo persistTo, final ReplicateTo replicateTo) {
Observable prependResult = prepend(document);
if (persistTo == PersistTo.NONE && replicateTo == ReplicateTo.NONE) {
return prependResult;
}
return prependResult.flatMap(new Func1>() {
@Override
public Observable call(final D doc) {
return Observe
.call(core, bucket, doc.id(), doc.cas(), false, doc.mutationToken(), persistTo.value(), replicateTo.value(),
environment.observeIntervalDelay(), environment.retryStrategy())
.map(new Func1() {
@Override
public D call(Boolean aBoolean) {
return doc;
}
}).onErrorResumeNext(new Func1>() {
@Override
public Observable extends D> call(Throwable throwable) {
return Observable.error(new DurabilityException(
"Durability requirement failed: " + throwable.getMessage(),
throwable));
}
});
}
});
}
/*---------------------------*
* START OF SUB-DOCUMENT API *
*---------------------------*/
@Override
public AsyncLookupInBuilder lookupIn(String docId) {
return new AsyncLookupInBuilder(core, bucket, environment, subdocumentTranscoder, docId);
}
@Override
public AsyncMutateInBuilder mutateIn(String docId) {
return new AsyncMutateInBuilder(core, bucket, environment, subdocumentTranscoder, docId);
}
/*-------------------------*
* END OF SUB-DOCUMENT API *
*-------------------------*/
@Override
public Observable close() {
return Observable.defer(new Func0>() {
@Override
public Observable call() {
return core.send(new CloseBucketRequest(bucket));
}
}).map(new Func1() {
@Override
public Boolean call(CloseBucketResponse response) {
closed = true;
return response.status().isSuccess();
}
});
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public String toString() {
return "AsyncBucket[" + name() + "]";
}
@Override
public Observable invalidateQueryCache() {
return Observable.just(n1qlQueryExecutor.invalidateQueryCache());
}
}