com.couchbase.client.java.manager.view.AsyncViewIndexManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-client Show documentation
Show all versions of java-client Show documentation
The official Couchbase Java SDK
/*
* Copyright 2019 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.manager.view;
import com.couchbase.client.core.Core;
import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.cnc.RequestSpan;
import com.couchbase.client.core.cnc.TracingIdentifiers;
import com.couchbase.client.core.deps.com.fasterxml.jackson.core.type.TypeReference;
import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.JsonNode;
import com.couchbase.client.core.deps.com.fasterxml.jackson.databind.node.ObjectNode;
import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf;
import com.couchbase.client.core.deps.io.netty.buffer.Unpooled;
import com.couchbase.client.core.deps.io.netty.handler.codec.http.DefaultFullHttpRequest;
import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpHeaderValues;
import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpMethod;
import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpResponseStatus;
import com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpVersion;
import com.couchbase.client.core.error.CouchbaseException;
import com.couchbase.client.core.error.DesignDocumentNotFoundException;
import com.couchbase.client.core.error.HttpStatusCodeException;
import com.couchbase.client.core.error.context.ReducedViewErrorContext;
import com.couchbase.client.core.json.Mapper;
import com.couchbase.client.core.msg.ResponseStatus;
import com.couchbase.client.core.msg.manager.GenericManagerResponse;
import com.couchbase.client.core.msg.view.GenericViewRequest;
import com.couchbase.client.core.msg.view.GenericViewResponse;
import com.couchbase.client.core.retry.RetryStrategy;
import com.couchbase.client.java.CommonOptions;
import com.couchbase.client.java.manager.ManagerSupport;
import com.couchbase.client.java.view.DesignDocumentNamespace;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import static com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpMethod.DELETE;
import static com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpMethod.GET;
import static com.couchbase.client.core.deps.io.netty.handler.codec.http.HttpMethod.PUT;
import static com.couchbase.client.core.logging.RedactableArgument.redactMeta;
import static com.couchbase.client.core.util.CbStrings.removeStart;
import static com.couchbase.client.core.util.CbThrowables.findCause;
import static com.couchbase.client.core.util.UrlQueryStringBuilder.urlEncode;
import static com.couchbase.client.core.util.Validators.notNull;
import static com.couchbase.client.core.util.Validators.notNullOrEmpty;
import static com.couchbase.client.java.view.DesignDocumentNamespace.DEVELOPMENT;
import static com.couchbase.client.java.view.DesignDocumentNamespace.PRODUCTION;
import static com.couchbase.client.java.view.DesignDocumentNamespace.requireUnqualified;
import static com.couchbase.client.java.manager.view.DropDesignDocumentOptions.dropDesignDocumentOptions;
import static com.couchbase.client.java.manager.view.GetAllDesignDocumentsOptions.getAllDesignDocumentsOptions;
import static com.couchbase.client.java.manager.view.GetDesignDocumentOptions.getDesignDocumentOptions;
import static com.couchbase.client.java.manager.view.PublishDesignDocumentOptions.publishDesignDocumentOptions;
import static com.couchbase.client.java.manager.view.UpsertDesignDocumentOptions.upsertDesignDocumentOptions;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
public class AsyncViewIndexManager {
private final Core core;
private final String bucket;
private class ConfigManager extends ManagerSupport {
public ConfigManager() {
super(core);
}
public CompletableFuture sendRequest(HttpMethod method, String path,
CommonOptions>.BuiltCommonOptions options,
RequestSpan span) {
return super.sendRequest(method, path, options, span);
}
}
public AsyncViewIndexManager(Core core, String bucket) {
this.core = requireNonNull(core);
this.bucket = requireNonNull(bucket);
}
private String pathForDesignDocument(String name, DesignDocumentNamespace namespace) {
name = namespace.adjustName(requireUnqualified(name));
return "/" + urlEncode(bucket) + "/_design/" + urlEncode(name);
}
private String pathForAllDesignDocuments() {
return "/pools/default/buckets/" + urlEncode(bucket) + "/ddocs";
}
/**
* Returns all of the design documents in the specified namespace.
*
* @param namespace namespace to query
*/
public CompletableFuture> getAllDesignDocuments(final DesignDocumentNamespace namespace) {
return getAllDesignDocuments(namespace, getAllDesignDocumentsOptions());
}
/**
* Returns all of the design documents in the specified namespace.
*
* @param namespace namespace to query
* @param options additional optional arguments (timeout, retry, etc.)
*/
public CompletableFuture> getAllDesignDocuments(final DesignDocumentNamespace namespace,
final GetAllDesignDocumentsOptions options) {
notNull(namespace, "DesignDocumentNamespace", () -> new ReducedViewErrorContext(null, null, bucket));
notNull(options, "GetAllDesignDocumentsOptions", () -> new ReducedViewErrorContext(null, null, bucket));
GetAllDesignDocumentsOptions.Built built = options.build();
RequestSpan span = buildSpan(
TracingIdentifiers.SPAN_REQUEST_MV_GET_ALL_DD,
built.parentSpan().orElse(null)
);
span.setAttribute(TracingIdentifiers.ATTR_NAME, bucket);
return new ConfigManager().sendRequest(GET, pathForAllDesignDocuments(), built, span).thenApply(response -> {
// Unlike the other view management requests, this request goes through the config manager endpoint.
// That endpoint treats any complete HTTP response as a success, so it's up to us to check the status code.
if (response.status() != ResponseStatus.SUCCESS) {
throw new CouchbaseException("Failed to get all design documents; response status=" + response.status()
+ "; response body=" + new String(response.content(), UTF_8));
}
return parseAllDesignDocuments(Mapper.decodeIntoTree(response.content()), namespace);
});
}
private static List parseAllDesignDocuments(JsonNode node, DesignDocumentNamespace namespace) {
List result = new ArrayList<>();
node.get("rows").forEach(row -> {
String metaId = row.path("doc").path("meta").path("id").asText();
String ddocName = removeStart(metaId, "_design/");
if (namespace.contains(ddocName)) {
JsonNode ddocDef = row.path("doc").path("json");
result.add(parseDesignDocument(ddocName, ddocDef));
}
});
return result;
}
/**
* Returns the named design document from the specified namespace.
*
* @param name name of the design document to retrieve
* @param namespace namespace to look in
* @throws DesignDocumentNotFoundException if the namespace does not contain a document with the given name
*/
public CompletableFuture getDesignDocument(String name, DesignDocumentNamespace namespace) {
return getDesignDocument(name, namespace, getDesignDocumentOptions());
}
/**
* Returns the named design document from the specified namespace.
*
* @param name name of the design document to retrieve
* @param namespace namespace to look in
* @param options additional optional arguments (timeout, retry, etc.)
* @throws DesignDocumentNotFoundException if the namespace does not contain a document with the given name
*/
public CompletableFuture getDesignDocument(String name, DesignDocumentNamespace namespace, GetDesignDocumentOptions options) {
notNullOrEmpty(name, "Name", () -> new ReducedViewErrorContext(null, null, bucket));
notNull(namespace, "DesignDocumentNamespace", () -> new ReducedViewErrorContext(name, null, bucket));
notNull(options, "GetDesignDocumentOptions", () -> new ReducedViewErrorContext(name, null, bucket));
GetDesignDocumentOptions.Built built = options.build();
RequestSpan span = buildSpan(
TracingIdentifiers.SPAN_REQUEST_MV_GET_DD,
built.parentSpan().orElse(null)
);
return sendRequest(GET, pathForDesignDocument(name, namespace), built, span)
.exceptionally(t -> {
throw notFound(t)
? DesignDocumentNotFoundException.forName(name, namespace.toString())
: new CouchbaseException("Failed to get design document [" + redactMeta(name) + "] from namespace " + namespace, t);
})
.thenApply(response ->
parseDesignDocument(name, Mapper.decodeIntoTree(response.content())));
}
private static DesignDocument parseDesignDocument(final String name, final JsonNode node) {
ObjectNode viewsNode = (ObjectNode) node.path("views");
Map views = Mapper.convertValue(viewsNode, new TypeReference