com.yahoo.vespa.model.clients.ContainerDocumentApi Maven / Gradle / Ivy
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.clients;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig;
import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.ContainerThreadpool;
import com.yahoo.vespa.model.container.PlatformBundles;
import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.UserBindingPattern;
import org.w3c.dom.Element;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author Einar M R Rosenvinge
* @author bjorncs
*/
public class ContainerDocumentApi {
public static final String DOCUMENT_V1_PREFIX = "/document/v1";
public static final Path VESPACLIENT_CONTAINER_BUNDLE =
PlatformBundles.absoluteBundlePath("vespaclient-container-plugin");
private final boolean ignoreUndefinedFields;
public ContainerDocumentApi(DeployState ds, ContainerCluster> cluster, HandlerOptions handlerOptions,
boolean ignoreUndefinedFields, Set portOverride) {
this.ignoreUndefinedFields = ignoreUndefinedFields;
addRestApiHandler(cluster, handlerOptions, portOverride);
addFeedHandler(ds, cluster, handlerOptions, portOverride);
addVespaClientContainerBundle(cluster);
}
public static void addVespaClientContainerBundle(ContainerCluster> c) {
c.addPlatformBundle(VESPACLIENT_CONTAINER_BUNDLE);
}
private static void addFeedHandler(DeployState ds, ContainerCluster> cluster, HandlerOptions handlerOptions, Set portOverride) {
String bindingSuffix = ContainerCluster.RESERVED_URI_PREFIX + "/feedapi";
var executor = new Threadpool(ds, "feedapi-handler", handlerOptions.feedApiThreadpoolOptions);
var handler = newVespaClientHandler("com.yahoo.vespa.http.server.FeedHandler",
bindingSuffix, handlerOptions, executor, portOverride);
cluster.addComponent(handler);
}
private static void addRestApiHandler(ContainerCluster> cluster, HandlerOptions handlerOptions, Set portOverride) {
var handler = newVespaClientHandler("com.yahoo.document.restapi.resource.DocumentV1ApiHandler",
DOCUMENT_V1_PREFIX + "/*", handlerOptions, null, portOverride);
cluster.addComponent(handler);
// We need to include a dummy implementation of the previous restapi handler (using the same class name).
// The internal legacy test framework requires that the name of the old handler is listed in /ApplicationStatus.
var oldHandlerDummy = createHandler("com.yahoo.document.restapi.resource.RestApi", null);
cluster.addComponent(oldHandlerDummy);
}
public boolean ignoreUndefinedFields() { return ignoreUndefinedFields; }
private static Handler newVespaClientHandler(String componentId,
String bindingSuffix,
HandlerOptions handlerOptions,
Threadpool executor,
Set portOverride) {
Handler handler = createHandler(componentId, executor);
if (handlerOptions.bindings.isEmpty()) {
handler.addServerBindings(bindingPattern(bindingSuffix, portOverride));
handler.addServerBindings(bindingPattern(bindingSuffix + '/', portOverride));
} else {
for (String rootBinding : handlerOptions.bindings) {
String pathWithoutLeadingSlash = bindingSuffix.substring(1);
handler.addServerBindings(userBindingPattern(rootBinding + pathWithoutLeadingSlash, portOverride));
handler.addServerBindings(userBindingPattern(rootBinding + pathWithoutLeadingSlash + '/', portOverride));
}
}
return handler;
}
private static List bindingPattern(String path, Set ports) {
if (ports.isEmpty()) return List.of(SystemBindingPattern.fromHttpPath(path));
return ports.stream()
.map(p -> (BindingPattern)SystemBindingPattern.fromHttpPortAndPath(p, path))
.toList();
}
private static List userBindingPattern(String path, Set ports) {
UserBindingPattern bindingPattern = UserBindingPattern.fromPattern(path);
if (ports.isEmpty()) return List.of(bindingPattern);
return ports.stream()
.map(p -> (BindingPattern)bindingPattern.withOverriddenPort(p))
.toList();
}
private static Handler createHandler(String className, Threadpool executor) {
return new Handler(new ComponentModel(className, null, "vespaclient-container-plugin"),
executor);
}
public static final class HandlerOptions {
private final Collection bindings;
private final Element feedApiThreadpoolOptions;
public HandlerOptions(Collection bindings, Element feedApiThreadpoolOptions) {
this.bindings = Collections.unmodifiableCollection(bindings);
this.feedApiThreadpoolOptions = feedApiThreadpoolOptions;
}
}
private static class Threadpool extends ContainerThreadpool {
Threadpool(DeployState ds, String name, Element xml) { super(ds, name, xml); }
@Override
protected void setDefaultConfigValues(ContainerThreadpoolConfig.Builder builder) {
builder.maxThreads(-4)
.minThreads(-4)
.queueSize(500);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy