summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Musum <musum@verizonmedia.com>2020-08-18 10:39:52 +0200
committerHarald Musum <musum@verizonmedia.com>2020-08-18 10:39:52 +0200
commit9dc4c09252afbdb352805e87d54a3c4a75d4d49b (patch)
treeebc43a6e8fc2be1b071b56b3b4b8be3c36d3cca3
parentf201978bbe446989bd2b6b749ff4d6c42807026f (diff)
parentef6227ebc92c625081f703a806e0b0c2c02a5a1c (diff)
Merge branch 'master' into hmusum/move-methods-to-Session
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java14
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java10
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java80
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientProviderBuilder.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomHandlerBuilder.java40
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java19
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java12
-rwxr-xr-xconfig-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java18
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/BindingPattern.java90
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/DiscBindingsConfigGenerator.java15
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/FileStatusHandlerComponent.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/Handler.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/SystemBindingPattern.java26
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/UserBindingPattern.java26
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/docproc/ContainerDocproc.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/docproc/DocprocChains.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java42
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/Binding.java39
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterBinding.java32
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java12
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java17
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/processing/ProcessingChains.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/search/GUIHandler.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java31
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java7
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java104
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/component/BindingPatternTest.java53
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/http/FilterBindingsTest.java20
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java84
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java23
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java36
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java18
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java13
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java11
-rw-r--r--default_build_settings.cmake6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseTest.java1
-rw-r--r--parent/pom.xml13
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp1
-rw-r--r--searchlib/src/tests/common/location/geo_location_test.cpp279
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp15
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.cpp87
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.h4
-rw-r--r--searchlib/src/vespa/searchlib/common/locationiterators.cpp102
-rw-r--r--searchlib/src/vespa/searchlib/common/locationiterators.h12
-rw-r--r--searchlib/src/vespa/searchlib/fef/iqueryenvironment.h2
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.cpp36
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.h1
-rw-r--r--storage/src/vespa/storage/distributor/distributor.h11
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp2
-rw-r--r--storage/src/vespa/storage/distributor/operations/external/visitoroperation.h1
-rw-r--r--storage/src/vespa/storage/persistence/fieldvisitor.h2
-rw-r--r--storage/src/vespa/storage/persistence/testandsethelper.cpp4
-rw-r--r--storage/src/vespa/storage/storageserver/storagenodecontext.cpp2
-rw-r--r--storage/src/vespa/storage/storageserver/storagenodecontext.h2
-rw-r--r--storageapi/src/vespa/storageapi/message/visitor.cpp1
-rw-r--r--zkfacade/pom.xml1
-rw-r--r--zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java2
-rw-r--r--zkfacade/src/main/java/com/yahoo/vespa/curator/mock/MockCurator.java491
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/api/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/api/transaction/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/listen/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/recipes/atomic/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/recipes/barriers/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/recipes/cache/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/recipes/locks/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/framework/state/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/package-info.java2
-rw-r--r--zkfacade/src/main/java/org/apache/curator/retry/package-info.java2
72 files changed, 1223 insertions, 825 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
index f9338f9cb35..9ae9a158631 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java
@@ -7,6 +7,7 @@ import com.yahoo.container.handler.ThreadpoolConfig;
import com.yahoo.search.config.QrStartConfig;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
/**
* @author hmusum
@@ -39,7 +40,7 @@ public class LogserverContainerCluster extends ContainerCluster<LogserverContain
private void addLogHandler() {
Handler<?> logHandler = Handler.fromClassName(ContainerCluster.LOG_HANDLER_CLASS);
- logHandler.addServerBindings("http://*/logs");
+ logHandler.addServerBindings(SystemBindingPattern.fromHttpPath("/logs"));
addComponent(logHandler);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
index 08f4e2fa12f..5b3e4e1479e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/clustercontroller/ClusterControllerContainer.java
@@ -14,6 +14,7 @@ import com.yahoo.vespa.model.container.Container;
import com.yahoo.vespa.model.container.component.AccessLogComponent;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.xml.PlatformBundles;
import java.util.Set;
@@ -36,10 +37,10 @@ public class ClusterControllerContainer extends Container implements
super(parent, "" + index, index);
addHandler("clustercontroller-status",
"com.yahoo.vespa.clustercontroller.apps.clustercontroller.StatusHandler",
- "clustercontroller-status/*");
+ "/clustercontroller-status/*");
addHandler("clustercontroller-state-restapi-v2",
"com.yahoo.vespa.clustercontroller.apps.clustercontroller.StateRestApiV2Handler",
- "cluster/v2/*");
+ "/cluster/v2/*");
if (runStandaloneZooKeeper) {
addComponent("clustercontroller-zkrunner",
"com.yahoo.vespa.zookeeper.VespaZooKeeperServerImpl",
@@ -77,8 +78,8 @@ public class ClusterControllerContainer extends Container implements
return ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
}
- private void addHandler(Handler h, String binding) {
- h.addServerBindings("http://*/" + binding);
+ private void addHandler(Handler h, String path) {
+ h.addServerBindings(SystemBindingPattern.fromHttpPath(path));
super.addHandler(h);
}
@@ -96,9 +97,8 @@ public class ClusterControllerContainer extends Container implements
addComponent(new Component<>(createComponentModel(id, className, bundle)));
}
- private void addHandler(String id, String className, String binding) {
- addHandler(new Handler(createComponentModel(id, className, CLUSTERCONTROLLER_BUNDLE)),
- binding);
+ private void addHandler(String id, String className, String path) {
+ addHandler(new Handler(createComponentModel(id, className, CLUSTERCONTROLLER_BUNDLE)), path);
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
index 4dc9811a024..b5936887b50 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java
@@ -7,12 +7,12 @@ import ai.vespa.metricsproxy.core.MetricsConsumers;
import ai.vespa.metricsproxy.core.MetricsManager;
import ai.vespa.metricsproxy.core.MonitoringConfig;
import ai.vespa.metricsproxy.core.VespaMetrics;
-import ai.vespa.metricsproxy.http.metrics.MetricsV1Handler;
import ai.vespa.metricsproxy.http.application.ApplicationMetricsHandler;
import ai.vespa.metricsproxy.http.application.ApplicationMetricsRetriever;
import ai.vespa.metricsproxy.http.application.MetricsNodesConfig;
-import ai.vespa.metricsproxy.http.yamas.YamasHandler;
+import ai.vespa.metricsproxy.http.metrics.MetricsV1Handler;
import ai.vespa.metricsproxy.http.prometheus.PrometheusHandler;
+import ai.vespa.metricsproxy.http.yamas.YamasHandler;
import ai.vespa.metricsproxy.metric.ExternalMetrics;
import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensions;
import ai.vespa.metricsproxy.metric.dimensions.ApplicationDimensionsConfig;
@@ -38,6 +38,7 @@ import com.yahoo.vespa.model.admin.monitoring.MetricsConsumer;
import com.yahoo.vespa.model.admin.monitoring.Monitoring;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.xml.PlatformBundles;
import java.nio.file.Path;
@@ -129,8 +130,9 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC
static Handler<AbstractConfigProducer<?>> createMetricsHandler(Class<? extends ThreadedHttpRequestHandler> clazz, String bindingPath) {
Handler<AbstractConfigProducer<?>> metricsHandler = new Handler<>(
new ComponentModel(clazz.getName(), null, METRICS_PROXY_BUNDLE_NAME, null));
- metricsHandler.addServerBindings("http://*" + bindingPath,
- "http://*" + bindingPath + "/*");
+ metricsHandler.addServerBindings(
+ SystemBindingPattern.fromHttpPath(bindingPath),
+ SystemBindingPattern.fromHttpPath(bindingPath + "/*"));
return metricsHandler;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java
new file mode 100644
index 00000000000..249827b11d9
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java
@@ -0,0 +1,80 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.application.validation;
+
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+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.http.FilterBinding;
+import com.yahoo.vespa.model.container.http.Http;
+
+import java.util.logging.Level;
+
+import static com.yahoo.config.model.ConfigModelContext.ApplicationType.HOSTED_INFRASTRUCTURE;
+
+/**
+ * Validates URI bindings for filters and handlers
+ *
+ * @author bjorncs
+ */
+class UriBindingsValidator extends Validator {
+
+ @Override
+ public void validate(VespaModel model, DeployState deployState) {
+ for (ApplicationContainerCluster cluster : model.getContainerClusters().values()) {
+ for (Handler<?> handler : cluster.getHandlers()) {
+ for (BindingPattern binding : handler.getServerBindings()) {
+ validateUserBinding(binding, model, deployState);
+ }
+ }
+ Http http = cluster.getHttp();
+ if (http != null) {
+ for (FilterBinding binding : cluster.getHttp().getBindings()) {
+ validateUserBinding(binding.binding(), model, deployState);
+ }
+ }
+ }
+ }
+
+ private static void validateUserBinding(BindingPattern binding, VespaModel model, DeployState deployState) {
+ validateScheme(binding, deployState);
+ if (isHostedApplication(model, deployState)) {
+ validateHostedApplicationUserBinding(binding);
+ }
+ }
+
+ private static void validateScheme(BindingPattern binding, DeployState deployState) {
+ if (binding.scheme().equals("https")) {
+ String message = createErrorMessage(
+ binding, "'https' bindings are deprecated, use 'http' instead to bind to both http and https traffic.");
+ deployState.getDeployLogger().log(Level.WARNING, message);
+ }
+ }
+
+ private static void validateHostedApplicationUserBinding(BindingPattern binding) {
+ // only perform these validation for used-generated bindings
+ // bindings produced by the hosted config model amender will violate some of the rules below
+ if (binding instanceof SystemBindingPattern) return;
+
+ if (binding.port().isPresent()) {
+ throw new IllegalArgumentException(createErrorMessage(binding, "binding with port is not allowed"));
+ }
+ if (!binding.host().equals(BindingPattern.WILDCARD_PATTERN)) {
+ throw new IllegalArgumentException(createErrorMessage(binding, "only binding with wildcard ('*') for hostname is allowed"));
+ }
+ if (!binding.scheme().equals("http") && !binding.scheme().equals("https")) {
+ throw new IllegalArgumentException(createErrorMessage(binding, "only 'http' is allowed as scheme"));
+ }
+ }
+
+ private static boolean isHostedApplication(VespaModel model, DeployState deployState) {
+ return deployState.isHosted() && model.getAdmin().getApplicationType() != HOSTED_INFRASTRUCTURE;
+ }
+
+ private static String createErrorMessage(BindingPattern binding, String message) {
+ return String.format("For binding '%s': %s", binding.patternString(), message);
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
index 22dd0289390..3a4dee300da 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
@@ -61,6 +61,7 @@ public class Validation {
new AccessControlFilterValidator().validate(model, deployState);
new CloudWatchValidator().validate(model, deployState);
new AwsAccessControlValidator().validate(model, deployState);
+ new UriBindingsValidator().validate(model, deployState);
List<ConfigChangeAction> result = Collections.emptyList();
if (deployState.getProperties().isFirstTimeDeployment()) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientProviderBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientProviderBuilder.java
index 11fab0ada29..0fdd1af56f3 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientProviderBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientProviderBuilder.java
@@ -2,11 +2,12 @@
package com.yahoo.vespa.model.builder.xml.dom;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.text.XML;
import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.text.XML;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
import org.w3c.dom.Element;
/**
@@ -24,10 +25,10 @@ public class DomClientProviderBuilder extends DomHandlerBuilder {
Handler<? super Component<?, ?>> client = createHandler(clientElement);
for (Element binding : XML.getChildren(clientElement, "binding"))
- client.addClientBindings(XML.getValue(binding));
+ client.addClientBindings(UserBindingPattern.fromPattern(XML.getValue(binding)));
for (Element serverBinding : XML.getChildren(clientElement, "serverBinding"))
- client.addServerBindings(XML.getValue(serverBinding));
+ client.addServerBindings(UserBindingPattern.fromPattern(XML.getValue(serverBinding)));
DomComponentBuilder.addChildren(deployState, parent, clientElement, client);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomHandlerBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomHandlerBuilder.java
index ac6d089cf24..145535fe06f 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomHandlerBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomHandlerBuilder.java
@@ -8,8 +8,10 @@ import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.text.XML;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
import com.yahoo.vespa.model.container.xml.BundleInstantiationSpecificationBuilder;
import org.w3c.dom.Element;
@@ -27,11 +29,14 @@ import static java.util.logging.Level.INFO;
*/
public class DomHandlerBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Handler> {
- private static final Set<String> reservedBindings = Set.of(METRICS_V2_HANDLER_BINDING_1,
- METRICS_V2_HANDLER_BINDING_2,
- STATE_HANDLER_BINDING_1,
- STATE_HANDLER_BINDING_2,
- VIP_HANDLER_BINDING);
+ private static final Set<BindingPattern> reservedBindings =
+ Set.of(
+ METRICS_V2_HANDLER_BINDING_1,
+ METRICS_V2_HANDLER_BINDING_2,
+ STATE_HANDLER_BINDING_1,
+ STATE_HANDLER_BINDING_2,
+ VIP_HANDLER_BINDING);
+
private final ApplicationContainerCluster cluster;
public DomHandlerBuilder(ApplicationContainerCluster cluster) {
@@ -43,10 +48,10 @@ public class DomHandlerBuilder extends VespaDomBuilder.DomConfigProducerBuilder<
Handler<? super Component<?, ?>> handler = createHandler(handlerElement);
for (Element binding : XML.getChildren(handlerElement, "binding"))
- addServerBinding(handler, XML.getValue(binding), deployState.getDeployLogger());
+ addServerBinding(handler, UserBindingPattern.fromPattern(XML.getValue(binding)), deployState.getDeployLogger());
for (Element clientBinding : XML.getChildren(handlerElement, "clientBinding"))
- handler.addClientBindings(XML.getValue(clientBinding));
+ handler.addClientBindings(UserBindingPattern.fromPattern(XML.getValue(clientBinding)));
DomComponentBuilder.addChildren(deployState, parent, handlerElement, handler);
@@ -58,27 +63,30 @@ public class DomHandlerBuilder extends VespaDomBuilder.DomConfigProducerBuilder<
return new Handler<>(new ComponentModel(bundleSpec));
}
- private void addServerBinding(Handler<? super Component<?, ?>> handler, String binding, DeployLogger log) {
+ private void addServerBinding(Handler<? super Component<?, ?>> handler, BindingPattern binding, DeployLogger log) {
throwIfBindingIsReserved(binding, handler);
handler.addServerBindings(binding);
removeExistingServerBinding(binding, handler, log);
}
- private void throwIfBindingIsReserved(String binding, Handler<?> newHandler) {
+ private void throwIfBindingIsReserved(BindingPattern binding, Handler<?> newHandler) {
for (var reserved : reservedBindings) {
- if (binding.equals(reserved)) {
- throw new IllegalArgumentException("Binding '" + binding + "' is a reserved Vespa binding and " +
+ if (binding.hasSamePattern(reserved)) {
+ throw new IllegalArgumentException("Binding '" + binding.patternString() + "' is a reserved Vespa binding and " +
"cannot be used by handler: " + newHandler.getComponentId());
}
}
}
- private void removeExistingServerBinding(String binding, Handler<?> newHandler, DeployLogger log) {
+ private void removeExistingServerBinding(BindingPattern binding, Handler<?> newHandler, DeployLogger log) {
for (var handler : cluster.getHandlers()) {
- if (handler.getServerBindings().contains(binding)) {
- handler.removeServerBinding(binding);
- log.log(INFO, "Binding '" + binding + "' was already in use by handler '" +
- handler.getComponentId() + "', but will now be taken over by handler: " + newHandler.getComponentId());
+ for (BindingPattern serverBinding : handler.getServerBindings()) {
+ if (serverBinding.hasSamePattern(binding)) {
+ handler.removeServerBinding(serverBinding);
+ log.log(INFO, "Binding '" + binding.patternString() + "' was already in use by handler '" +
+ handler.getComponentId() + "', but will now be taken over by handler: " + newHandler.getComponentId());
+
+ }
}
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
index 58f03bffb30..159a87be27d 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
@@ -6,6 +6,8 @@ import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.vespa.model.container.ContainerCluster;
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 java.util.Collection;
import java.util.Collections;
@@ -24,7 +26,7 @@ public class ContainerDocumentApi {
}
private void setupHandlers(ContainerCluster cluster) {
- cluster.addComponent(newVespaClientHandler("com.yahoo.document.restapi.resource.RestApi", "document/v1/*"));
+ cluster.addComponent(newVespaClientHandler("com.yahoo.document.restapi.resource.RestApi", "/document/v1/*"));
cluster.addComponent(newVespaClientHandler("com.yahoo.vespa.http.server.FeedHandler", ContainerCluster.RESERVED_URI_PREFIX + "/feedapi"));
}
@@ -32,9 +34,18 @@ public class ContainerDocumentApi {
Handler<AbstractConfigProducer<?>> handler = new Handler<>(new ComponentModel(
BundleInstantiationSpecification.getFromStrings(componentId, null, vespaClientBundleSpecification), ""));
- for (String rootBinding : options.bindings) {
- handler.addServerBindings(rootBinding + bindingSuffix,
- rootBinding + bindingSuffix + '/');
+ if (options.bindings.isEmpty()) {
+ handler.addServerBindings(
+ SystemBindingPattern.fromHttpPath(bindingSuffix),
+ SystemBindingPattern.fromHttpPath(bindingSuffix + '/'));
+ } else {
+ for (String rootBinding : options.bindings) {
+ String pathWithoutLeadingSlash = bindingSuffix.substring(1);
+ handler.addServerBindings(
+ UserBindingPattern.fromPattern(rootBinding + pathWithoutLeadingSlash),
+ UserBindingPattern.fromPattern(rootBinding + pathWithoutLeadingSlash + '/'));
+ }
+
}
return handler;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
index b0ac02d0fe8..1427fa492dc 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
@@ -22,10 +22,12 @@ import com.yahoo.search.config.QrStartConfig;
import com.yahoo.vespa.config.search.RankProfilesConfig;
import com.yahoo.vespa.config.search.core.RankingConstantsConfig;
import com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainer;
+import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.ConfigProducerGroup;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.Servlet;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.jersey.Jersey2Servlet;
import com.yahoo.vespa.model.container.jersey.RestApi;
import com.yahoo.vespa.model.container.xml.PlatformBundles;
@@ -55,12 +57,12 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
MetricsProxyApiConfig.Producer {
public static final String METRICS_V2_HANDLER_CLASS = MetricsV2Handler.class.getName();
- public static final String METRICS_V2_HANDLER_BINDING_1 = "http://*" + MetricsV2Handler.V2_PATH;
- public static final String METRICS_V2_HANDLER_BINDING_2 = METRICS_V2_HANDLER_BINDING_1 + "/*";
+ public static final BindingPattern METRICS_V2_HANDLER_BINDING_1 = SystemBindingPattern.fromHttpPath(MetricsV2Handler.V2_PATH);
+ public static final BindingPattern METRICS_V2_HANDLER_BINDING_2 = SystemBindingPattern.fromHttpPath(MetricsV2Handler.V2_PATH + "/*");
public static final String PROMETHEUS_V1_HANDLER_CLASS = PrometheusV1Handler.class.getName();
- private static final String PROMETHEUS_V1_HANDLER_BINDING_1 = "http://*" + PrometheusV1Handler.V1_PATH;
- private static final String PROMETHEUS_V1_HANDLER_BINDING_2 = PROMETHEUS_V1_HANDLER_BINDING_1 + "/*";
+ private static final BindingPattern PROMETHEUS_V1_HANDLER_BINDING_1 = SystemBindingPattern.fromHttpPath(PrometheusV1Handler.V1_PATH);
+ private static final BindingPattern PROMETHEUS_V1_HANDLER_BINDING_2 = SystemBindingPattern.fromHttpPath(PrometheusV1Handler.V1_PATH + "/*");
public static final int heapSizePercentageOfTotalNodeMemory = 60;
public static final int heapSizePercentageOfTotalNodeMemoryWhenCombinedCluster = 17;
@@ -125,7 +127,7 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
addMetricsHandler(PROMETHEUS_V1_HANDLER_CLASS, PROMETHEUS_V1_HANDLER_BINDING_1, PROMETHEUS_V1_HANDLER_BINDING_2);
}
- private void addMetricsHandler(String handlerClass, String rootBinding, String innerBinding) {
+ private void addMetricsHandler(String handlerClass, BindingPattern rootBinding, BindingPattern innerBinding) {
Handler<AbstractConfigProducer<?>> handler = new Handler<>(
new ComponentModel(handlerClass, null, null, null));
handler.addServerBindings(rootBinding, innerBinding);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
index 240157fb7aa..8bb456ab7e7 100755
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
@@ -39,6 +39,7 @@ import com.yahoo.vespa.model.Service;
import com.yahoo.vespa.model.admin.monitoring.Monitoring;
import com.yahoo.vespa.model.clients.ContainerDocumentApi;
import com.yahoo.vespa.model.container.component.AccessLogComponent;
+import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.container.component.ComponentGroup;
import com.yahoo.vespa.model.container.component.ComponentsConfigGenerator;
@@ -47,6 +48,7 @@ import com.yahoo.vespa.model.container.component.FileStatusHandlerComponent;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.component.StatisticsComponent;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
import com.yahoo.vespa.model.container.docproc.DocprocChains;
@@ -107,7 +109,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
* normal compatibility concerns only applies to libraries using the URIs in
* question, not contents served from the URIs themselves.
*/
- public static final String RESERVED_URI_PREFIX = "reserved-for-internal-use";
+ public static final String RESERVED_URI_PREFIX = "/reserved-for-internal-use";
public static final String APPLICATION_STATUS_HANDLER_CLASS = "com.yahoo.container.handler.observability.ApplicationStatusHandler";
public static final String BINDINGS_OVERVIEW_HANDLER_CLASS = BindingsOverviewHandler.class.getName();
@@ -117,13 +119,13 @@ public abstract class ContainerCluster<CONTAINER extends Container>
public static final String G1GC = "-XX:+UseG1GC -XX:MaxTenuringThreshold=15";
public static final String STATE_HANDLER_CLASS = "com.yahoo.container.jdisc.state.StateHandler";
- public static final String STATE_HANDLER_BINDING_1 = "http://*" + StateHandler.STATE_API_ROOT;
- public static final String STATE_HANDLER_BINDING_2 = STATE_HANDLER_BINDING_1 + "/*";
+ public static final BindingPattern STATE_HANDLER_BINDING_1 = SystemBindingPattern.fromHttpPath(StateHandler.STATE_API_ROOT);
+ public static final BindingPattern STATE_HANDLER_BINDING_2 = SystemBindingPattern.fromHttpPath(StateHandler.STATE_API_ROOT + "/*");
public static final String ROOT_HANDLER_PATH = "/";
- public static final String ROOT_HANDLER_BINDING = "http://*" + ROOT_HANDLER_PATH;
+ public static final BindingPattern ROOT_HANDLER_BINDING = SystemBindingPattern.fromHttpPath(ROOT_HANDLER_PATH);
- public static final String VIP_HANDLER_BINDING = "http://*/status.html";
+ public static final BindingPattern VIP_HANDLER_BINDING = SystemBindingPattern.fromHttpPath("/status.html");
private final String name;
@@ -234,7 +236,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
Handler<AbstractConfigProducer<?>> statusHandler = new Handler<>(
new ComponentModel(BundleInstantiationSpecification.getInternalHandlerSpecificationFromStrings(
APPLICATION_STATUS_HANDLER_CLASS, null), null));
- statusHandler.addServerBindings("http://*/ApplicationStatus");
+ statusHandler.addServerBindings(SystemBindingPattern.fromHttpPath("/ApplicationStatus"));
addComponent(statusHandler);
}
@@ -309,7 +311,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
containers.forEach(this::addContainer);
}
- public void setProcessingChains(ProcessingChains processingChains, String... serverBindings) {
+ public void setProcessingChains(ProcessingChains processingChains, BindingPattern... serverBindings) {
if (this.processingChains != null)
throw new IllegalStateException("ProcessingChains should only be set once.");
@@ -320,7 +322,7 @@ public abstract class ContainerCluster<CONTAINER extends Container>
processingChains,
"com.yahoo.processing.handler.ProcessingHandler");
- for (String binding: serverBindings)
+ for (BindingPattern binding: serverBindings)
processingHandler.addServerBindings(binding);
addComponent(processingHandler);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java
index 6b4f8d486ec..72f1921e6a2 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerModelEvaluation.java
@@ -7,6 +7,7 @@ import com.yahoo.searchdefinition.derived.RankProfileList;
import com.yahoo.vespa.config.search.RankProfilesConfig;
import com.yahoo.vespa.config.search.core.RankingConstantsConfig;
import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import java.util.List;
import java.util.Objects;
@@ -21,7 +22,7 @@ public class ContainerModelEvaluation implements RankProfilesConfig.Producer, Ra
private final static String BUNDLE_NAME = "model-evaluation";
private final static String EVALUATOR_NAME = ModelsEvaluator.class.getName();
private final static String REST_HANDLER_NAME = "ai.vespa.models.handler.ModelsEvaluationHandler";
- private final static String REST_BINDING = "model-evaluation/v1";
+ private final static String REST_BINDING_PATH = "/model-evaluation/v1";
/** Global rank profiles, aka models */
private final RankProfileList rankProfileList;
@@ -48,8 +49,9 @@ public class ContainerModelEvaluation implements RankProfilesConfig.Producer, Ra
public static Handler<?> getHandler() {
Handler<?> handler = new Handler<>(new ComponentModel(REST_HANDLER_NAME, null, BUNDLE_NAME));
- handler.addServerBindings("http://*/" + REST_BINDING,
- "http://*/" + REST_BINDING + "/*");
+ handler.addServerBindings(
+ SystemBindingPattern.fromHttpPath(REST_BINDING_PATH),
+ SystemBindingPattern.fromHttpPath(REST_BINDING_PATH + "/*"));
return handler;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/BindingPattern.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/BindingPattern.java
new file mode 100644
index 00000000000..c8b9d3293a7
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/BindingPattern.java
@@ -0,0 +1,90 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.component;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * URI binding pattern used by filter and handler bindings.
+ *
+ * @author bjorncs
+ */
+public abstract class BindingPattern implements Comparable<BindingPattern> {
+
+ private static final Pattern BINDING_PATTERN =
+ Pattern.compile("([^:]+)://([^:/]+)(:((\\*)|([0-9]+)))?(/.*)", Pattern.UNICODE_CASE | Pattern.CANON_EQ);
+
+ public static final String WILDCARD_PATTERN = "*";
+
+ private final String scheme;
+ private final String host;
+ private final String port;
+ private final String path;
+
+ protected BindingPattern(
+ String scheme,
+ String host,
+ String port,
+ String path) {
+ this.scheme = Objects.requireNonNull(scheme, "Scheme in binding must be specified");
+ this.host = Objects.requireNonNull(host, "Host must be specified");
+ this.port = port;
+ this.path = validatePath(path);
+ }
+
+ protected BindingPattern(String binding) {
+ Matcher matcher = BINDING_PATTERN.matcher(binding);
+ if (!matcher.matches()) throw new IllegalArgumentException("Invalid binding: " + binding);
+ this.scheme = matcher.group(1);
+ this.host = matcher.group(2);
+ this.port = matcher.group(4);
+ this.path = matcher.group(7);
+ }
+
+ private static String validatePath(String path) {
+ Objects.requireNonNull(path, "Path must be specified");
+ if (!path.startsWith("/")) throw new IllegalArgumentException("Path must have '/' as prefix:" + path);
+ return path;
+ }
+
+ public String scheme() { return scheme; }
+ public String host() { return host; }
+ public Optional<String> port() { return Optional.ofNullable(port); }
+ public String path() { return path; }
+
+ public String patternString() {
+ StringBuilder builder = new StringBuilder(scheme).append("://").append(host);
+ if (port != null) {
+ builder.append(':').append(port);
+ }
+ return builder.append(path).toString();
+ }
+
+ /** Compares the underlying pattern string for equality */
+ public boolean hasSamePattern(BindingPattern other) { return this.patternString().equals(other.patternString()); }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BindingPattern that = (BindingPattern) o;
+ return Objects.equals(scheme, that.scheme) &&
+ Objects.equals(host, that.host) &&
+ Objects.equals(port, that.port) &&
+ Objects.equals(path, that.path);
+ }
+
+ @Override public int hashCode() { return Objects.hash(scheme, host, port, path); }
+
+ @Override
+ public int compareTo(BindingPattern o) {
+ return Comparator.comparing(BindingPattern::scheme)
+ .thenComparing(BindingPattern::host)
+ .thenComparing(pattern -> pattern.port().orElse(null))
+ .thenComparing(BindingPattern::path)
+ .compare(this, o);
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/DiscBindingsConfigGenerator.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/DiscBindingsConfigGenerator.java
index d7e393ee474..02face328d9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/DiscBindingsConfigGenerator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/DiscBindingsConfigGenerator.java
@@ -1,13 +1,16 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.component;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
import static com.yahoo.container.jdisc.JdiscBindingsConfig.Handlers;
+import static java.util.stream.Collectors.toList;
/**
* @author gjoranv
- * @since 5.1.8
*/
public class DiscBindingsConfigGenerator {
@@ -26,7 +29,11 @@ public class DiscBindingsConfigGenerator {
return Collections.singletonMap(handler.model.getComponentId().stringValue(),
new Handlers.Builder()
- .serverBindings(handler.getServerBindings())
- .clientBindings(handler.getClientBindings()));
+ .serverBindings(toStrings(handler.getServerBindings()))
+ .clientBindings(toStrings(handler.getClientBindings())));
+ }
+
+ private static Collection<String> toStrings(Collection<BindingPattern> bindings) {
+ return bindings.stream().map(BindingPattern::patternString).collect(toList());
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/FileStatusHandlerComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/FileStatusHandlerComponent.java
index 3d9a1b2e665..839594502c6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/FileStatusHandlerComponent.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/FileStatusHandlerComponent.java
@@ -15,7 +15,7 @@ public class FileStatusHandlerComponent extends Handler implements VipStatusConf
private final String fileName;
- public FileStatusHandlerComponent(String id, String fileName, String... bindings) {
+ public FileStatusHandlerComponent(String id, String fileName, BindingPattern... bindings) {
super(new ComponentModel(id, CLASS, null, null));
this.fileName = fileName;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/Handler.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/Handler.java
index 82484e07773..efee5c6a9a0 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/Handler.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/Handler.java
@@ -1,9 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.component;
-import com.yahoo.container.bundle.BundleInstantiationSpecification;
-import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.osgi.provider.model.ComponentModel;
import java.util.ArrayList;
import java.util.Arrays;
@@ -23,8 +22,8 @@ import java.util.Set;
*/
public class Handler<CHILD extends AbstractConfigProducer<?>> extends Component<CHILD, ComponentModel> {
- private Set<String> serverBindings = new LinkedHashSet<>();
- private List<String> clientBindings = new ArrayList<>();
+ private final Set<BindingPattern> serverBindings = new LinkedHashSet<>();
+ private final List<BindingPattern> clientBindings = new ArrayList<>();
public Handler(ComponentModel model) {
super(model);
@@ -34,27 +33,23 @@ public class Handler<CHILD extends AbstractConfigProducer<?>> extends Component<
return new Handler<>(new ComponentModel(className, null, null, null));
}
- public static Handler<AbstractConfigProducer<?>> getVespaHandlerFromClassName(String className) {
- return new Handler<>(new ComponentModel(BundleInstantiationSpecification.getInternalHandlerSpecificationFromStrings(className, null), null));
- }
-
- public void addServerBindings(String... bindings) {
+ public void addServerBindings(BindingPattern... bindings) {
serverBindings.addAll(Arrays.asList(bindings));
}
- public void removeServerBinding(String binding) {
+ public void removeServerBinding(BindingPattern binding) {
serverBindings.remove(binding);
}
- public void addClientBindings(String... bindings) {
+ public void addClientBindings(BindingPattern... bindings) {
clientBindings.addAll(Arrays.asList(bindings));
}
- public final Set<String> getServerBindings() {
+ public final Set<BindingPattern> getServerBindings() {
return Collections.unmodifiableSet(serverBindings);
}
- public final List<String> getClientBindings() {
+ public final List<BindingPattern> getClientBindings() {
return Collections.unmodifiableList(clientBindings);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/SystemBindingPattern.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/SystemBindingPattern.java
new file mode 100644
index 00000000000..559651b3b4f
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/SystemBindingPattern.java
@@ -0,0 +1,26 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.component;
+
+/**
+ * A {@link BindingPattern} which is implicitly constructed by the model, e.g for built-in handlers and filter chains.
+ *
+ * @author bjorncs
+ */
+public class SystemBindingPattern extends BindingPattern {
+
+ private SystemBindingPattern(String scheme, String host, String port, String path) { super(scheme, host, port, path); }
+ private SystemBindingPattern(String binding) { super(binding); }
+
+ public static SystemBindingPattern fromHttpPath(String path) { return new SystemBindingPattern("http", "*", null, path);}
+ public static SystemBindingPattern fromPattern(String binding) { return new SystemBindingPattern(binding);}
+
+ @Override
+ public String toString() {
+ return "SystemBindingPattern{" +
+ "scheme='" + scheme() + '\'' +
+ ", host='" + host() + '\'' +
+ ", port='" + port().orElse(null) + '\'' +
+ ", path='" + path() + '\'' +
+ '}';
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/UserBindingPattern.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/UserBindingPattern.java
new file mode 100644
index 00000000000..43f57fa0343
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/UserBindingPattern.java
@@ -0,0 +1,26 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.component;
+
+/**
+ * A {@link BindingPattern} which is constructed directly from a user provided 'binding' element from services.xml.
+ *
+ * @author bjorncs
+ */
+public class UserBindingPattern extends BindingPattern {
+
+ private UserBindingPattern(String scheme, String host, String port, String path) { super(scheme, host, port, path); }
+ private UserBindingPattern(String binding) { super(binding); }
+
+ public static UserBindingPattern fromHttpPath(String path) { return new UserBindingPattern("http", "*", null, path); }
+ public static UserBindingPattern fromPattern(String binding) { return new UserBindingPattern(binding); }
+
+ @Override
+ public String toString() {
+ return "UserBindingPattern{" +
+ "scheme='" + scheme() + '\'' +
+ ", host='" + host() + '\'' +
+ ", port='" + port().orElse(null) + '\'' +
+ ", path='" + path() + '\'' +
+ '}';
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/ContainerDocproc.java b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/ContainerDocproc.java
index d4b4dcea78e..82061a0425f 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/ContainerDocproc.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/ContainerDocproc.java
@@ -9,6 +9,7 @@ import com.yahoo.container.jdisc.config.SessionConfig;
import com.yahoo.docproc.jdisc.messagebus.MbusRequestContext;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.component.ContainerSubsystem;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import java.util.HashMap;
import java.util.Map;
@@ -44,7 +45,7 @@ public class ContainerDocproc extends ContainerSubsystem<DocprocChains>
private void addSource(
final ContainerCluster cluster, final String name, final SessionConfig.Type.Enum type) {
final MbusClient mbusClient = new MbusClient(name, type);
- mbusClient.addClientBindings("mbus://*/" + mbusClient.getSessionName());
+ mbusClient.addClientBindings(SystemBindingPattern.fromPattern("mbus://*/" + mbusClient.getSessionName()));
cluster.addComponent(mbusClient);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/DocprocChains.java b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/DocprocChains.java
index 5d08a0a6998..68dc2518c23 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/DocprocChains.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/docproc/DocprocChains.java
@@ -7,6 +7,7 @@ import com.yahoo.container.jdisc.config.SessionConfig;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.component.Component;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.chain.Chains;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
@@ -38,12 +39,12 @@ public class DocprocChains extends Chains<DocprocChain> {
}
private void addServerAndClientForChain(ApplicationContainerCluster cluster, DocprocChain docprocChain) {
- docprocHandler.addServerBindings("mbus://*/" + docprocChain.getSessionName());
+ docprocHandler.addServerBindings(SystemBindingPattern.fromPattern("mbus://*/" + docprocChain.getSessionName()));
cluster.addMbusServer(ComponentId.fromString(docprocChain.getSessionName()));
MbusClient client = new MbusClient(docprocChain.getSessionName(), SessionConfig.Type.INTERMEDIATE);
- client.addClientBindings("mbus://*/" + client.getSessionName());
+ client.addClientBindings(SystemBindingPattern.fromPattern("mbus://*/" + client.getSessionName()));
addComponent(client);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
index 9676b8b1e4a..87c6d41c80d 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
@@ -3,12 +3,13 @@ package com.yahoo.vespa.model.container.http;
import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
-import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.ContainerCluster;
+import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.FileStatusHandlerComponent;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.Servlet;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import java.util.ArrayList;
import java.util.Collection;
@@ -43,14 +44,12 @@ public final class AccessControl {
private String domain;
private boolean readEnabled = false;
private boolean writeEnabled = true;
- private final Set<String> excludeBindings = new LinkedHashSet<>();
+ private final Set<BindingPattern> excludeBindings = new LinkedHashSet<>();
private Collection<Handler<?>> handlers = Collections.emptyList();
private Collection<Servlet> servlets = Collections.emptyList();
- private final DeployLogger logger;
- public Builder(String domain, DeployLogger logger) {
+ public Builder(String domain) {
this.domain = domain;
- this.logger = logger;
}
public Builder readEnabled(boolean readEnabled) {
@@ -63,7 +62,7 @@ public final class AccessControl {
return this;
}
- public Builder excludeBinding(String binding) {
+ public Builder excludeBinding(BindingPattern binding) {
this.excludeBindings.add(binding);
return this;
}
@@ -76,35 +75,32 @@ public final class AccessControl {
public AccessControl build() {
return new AccessControl(domain, writeEnabled, readEnabled,
- excludeBindings, servlets, handlers, logger);
+ excludeBindings, servlets, handlers);
}
}
public final String domain;
public final boolean readEnabled;
public final boolean writeEnabled;
- private final Set<String> excludedBindings;
+ private final Set<BindingPattern> excludedBindings;
private final Collection<Handler<?>> handlers;
private final Collection<Servlet> servlets;
- private final DeployLogger logger;
private AccessControl(String domain,
boolean writeEnabled,
boolean readEnabled,
- Set<String> excludedBindings,
+ Set<BindingPattern> excludedBindings,
Collection<Servlet> servlets,
- Collection<Handler<?>> handlers,
- DeployLogger logger) {
+ Collection<Handler<?>> handlers) {
this.domain = domain;
this.readEnabled = readEnabled;
this.writeEnabled = writeEnabled;
this.excludedBindings = Collections.unmodifiableSet(excludedBindings);
this.handlers = handlers;
this.servlets = servlets;
- this.logger = logger;
}
- public List<Binding> getBindings() {
+ public List<FilterBinding> getBindings() {
return Stream.concat(getHandlerBindings(), getServletBindings())
.collect(Collectors.toCollection(ArrayList::new));
}
@@ -113,18 +109,18 @@ public final class AccessControl {
return cluster.getHandlers().stream().anyMatch(AccessControl::handlerNeedsProtection);
}
- private Stream<Binding> getHandlerBindings() {
+ private Stream<FilterBinding> getHandlerBindings() {
return handlers.stream()
.filter(this::shouldHandlerBeProtected)
.flatMap(handler -> handler.getServerBindings().stream())
- .map(binding -> accessControlBinding(binding, logger));
+ .map(binding -> accessControlBinding(binding));
}
- private Stream<Binding> getServletBindings() {
+ private Stream<FilterBinding> getServletBindings() {
return servlets.stream()
.filter(this::shouldServletBeProtected)
.flatMap(AccessControl::servletBindings)
- .map(binding -> accessControlBinding(binding, logger));
+ .map(binding -> accessControlBinding(binding));
}
private boolean shouldHandlerBeProtected(Handler<?> handler) {
@@ -140,12 +136,12 @@ public final class AccessControl {
return servletBindings(servlet).noneMatch(excludedBindings::contains);
}
- private static Binding accessControlBinding(String binding, DeployLogger logger) {
- return Binding.create(new ComponentSpecification(ACCESS_CONTROL_CHAIN_ID.stringValue()), binding, logger);
+ private static FilterBinding accessControlBinding(BindingPattern binding) {
+ return FilterBinding.create(new ComponentSpecification(ACCESS_CONTROL_CHAIN_ID.stringValue()), binding);
}
- private static Stream<String> servletBindings(Servlet servlet) {
- return Stream.of("http://*/").map(protocol -> protocol + servlet.bindingPath);
+ private static Stream<BindingPattern> servletBindings(Servlet servlet) {
+ return Stream.of(SystemBindingPattern.fromHttpPath("/" + servlet.bindingPath));
}
private static boolean handlerNeedsProtection(Handler<?> handler) {
@@ -153,7 +149,7 @@ public final class AccessControl {
}
private static boolean hasNonMbusBinding(Handler<?> handler) {
- return handler.getServerBindings().stream().anyMatch(binding -> ! binding.startsWith("mbus"));
+ return handler.getServerBindings().stream().anyMatch(binding -> ! binding.scheme().equals("mbus"));
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Binding.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/Binding.java
deleted file mode 100644
index 28f4949f210..00000000000
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Binding.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.model.container.http;
-
-import com.yahoo.component.ComponentSpecification;
-import com.yahoo.config.application.api.DeployLogger;
-
-import java.util.logging.Level;
-
-/**
- * @author bjorncs
- */
-public class Binding {
-
- private final ComponentSpecification filterId;
- private final String binding;
-
- private Binding(ComponentSpecification filterId, String binding) {
- this.filterId = filterId;
- this.binding = binding;
- }
-
- public static Binding create(ComponentSpecification filterId, String binding, DeployLogger logger) {
- if (binding.startsWith("https://")) {
- logger.log(Level.WARNING, String.format("For binding '%s' on '%s': 'https' bindings are deprecated, " +
- "use 'http' instead to bind to both http and https traffic.",
- binding, filterId));
- }
- return new Binding(filterId, binding);
- }
-
- public ComponentSpecification filterId() {
- return filterId;
- }
-
- public String binding() {
- return binding;
- }
-
-}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterBinding.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterBinding.java
new file mode 100644
index 00000000000..8ae06b7cebd
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterBinding.java
@@ -0,0 +1,32 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.http;
+
+import com.yahoo.component.ComponentSpecification;
+import com.yahoo.vespa.model.container.component.BindingPattern;
+
+/**
+ * @author bjorncs
+ */
+public class FilterBinding {
+
+ private final ComponentSpecification filterId;
+ private final BindingPattern binding;
+
+ private FilterBinding(ComponentSpecification filterId, BindingPattern binding) {
+ this.filterId = filterId;
+ this.binding = binding;
+ }
+
+ public static FilterBinding create(ComponentSpecification filterId, BindingPattern binding) {
+ return new FilterBinding(filterId, binding);
+ }
+
+ public ComponentSpecification filterId() {
+ return filterId;
+ }
+
+ public BindingPattern binding() {
+ return binding;
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
index 0fcf7b2d06c..3155669527a 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
@@ -21,7 +21,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> implements ServerConfig.Producer {
private final FilterChains filterChains;
- private final List<Binding> bindings = new CopyOnWriteArrayList<>();
+ private final List<FilterBinding> bindings = new CopyOnWriteArrayList<>();
private volatile JettyHttpServer httpServer;
private volatile AccessControl accessControl;
@@ -64,7 +64,7 @@ public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> impl
setHttpServer(null);
}
- public List<Binding> getBindings() {
+ public List<FilterBinding> getBindings() {
return bindings;
}
@@ -74,16 +74,16 @@ public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> impl
@Override
public void getConfig(ServerConfig.Builder builder) {
- for (Binding binding : bindings) {
+ for (FilterBinding binding : bindings) {
builder.filter(new ServerConfig.Filter.Builder()
.id(binding.filterId().stringValue())
- .binding(binding.binding()));
+ .binding(binding.binding().patternString()));
}
}
@Override
public void validate() {
- if (((Collection<Binding>) bindings).isEmpty()) return;
+ if (((Collection<FilterBinding>) bindings).isEmpty()) return;
if (filterChains == null)
throw new IllegalArgumentException("Null FilterChains are not allowed when there are filter bindings");
@@ -91,7 +91,7 @@ public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> impl
ComponentRegistry<ChainedComponent<?>> filters = filterChains.componentsRegistry();
ComponentRegistry<Chain<Filter>> chains = filterChains.allChains();
- for (Binding binding: bindings) {
+ for (FilterBinding binding: bindings) {
if (filters.getComponent(binding.filterId()) == null && chains.getComponent(binding.filterId()) == null)
throw new RuntimeException("Can't find filter " + binding.filterId() + " for binding " + binding.binding());
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java
index bfde9b9add1..9d5fead7dfb 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java
@@ -13,9 +13,10 @@ import com.yahoo.vespa.model.builder.xml.dom.ModelElement;
import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.Container;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.http.AccessControl;
-import com.yahoo.vespa.model.container.http.Binding;
+import com.yahoo.vespa.model.container.http.FilterBinding;
import com.yahoo.vespa.model.container.http.FilterChains;
import com.yahoo.vespa.model.container.http.Http;
import org.w3c.dom.Element;
@@ -36,13 +37,13 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
@Override
protected Http doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element spec) {
FilterChains filterChains;
- List<Binding> bindings = new ArrayList<>();
+ List<FilterBinding> bindings = new ArrayList<>();
AccessControl accessControl = null;
Element filteringElem = XML.getChild(spec, "filtering");
if (filteringElem != null) {
filterChains = new FilterChainsBuilder().build(deployState, ancestor, filteringElem);
- bindings = readFilterBindings(filteringElem, deployState.getDeployLogger());
+ bindings = readFilterBindings(filteringElem);
Element accessControlElem = XML.getChild(filteringElem, "access-control");
if (accessControlElem != null) {
@@ -63,7 +64,7 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
private AccessControl buildAccessControl(DeployState deployState, AbstractConfigProducer ancestor, Element accessControlElem) {
AthenzDomain domain = getAccessControlDomain(deployState, accessControlElem);
- AccessControl.Builder builder = new AccessControl.Builder(domain.value(), deployState.getDeployLogger());
+ AccessControl.Builder builder = new AccessControl.Builder(domain.value());
getContainerCluster(ancestor).ifPresent(builder::setHandlers);
@@ -75,7 +76,7 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
Element excludeElem = XML.getChild(accessControlElem, "exclude");
if (excludeElem != null) {
XML.getChildren(excludeElem, "binding").stream()
- .map(XML::getValue)
+ .map(xml -> UserBindingPattern.fromPattern(XML.getValue(xml)))
.forEach(builder::excludeBinding);
}
return builder.build();
@@ -113,8 +114,8 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
return Optional.of((ApplicationContainerCluster) currentProducer);
}
- private List<Binding> readFilterBindings(Element filteringSpec, DeployLogger logger) {
- List<Binding> result = new ArrayList<>();
+ private List<FilterBinding> readFilterBindings(Element filteringSpec) {
+ List<FilterBinding> result = new ArrayList<>();
for (Element child: XML.getChildren(filteringSpec)) {
String tagName = child.getTagName();
@@ -123,7 +124,7 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
for (Element bindingSpec: XML.getChildren(child, "binding")) {
String binding = XML.getValue(bindingSpec);
- result.add(Binding.create(chainId, binding, logger));
+ result.add(FilterBinding.create(chainId, UserBindingPattern.fromPattern(binding)));
}
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/processing/ProcessingChains.java b/config-model/src/main/java/com/yahoo/vespa/model/container/processing/ProcessingChains.java
index 4fd79a4f335..f6b24bf9635 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/processing/ProcessingChains.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/processing/ProcessingChains.java
@@ -2,6 +2,8 @@
package com.yahoo.vespa.model.container.processing;
import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.vespa.model.container.component.BindingPattern;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.chain.Chains;
/**
@@ -11,7 +13,7 @@ import com.yahoo.vespa.model.container.component.chain.Chains;
*/
public class ProcessingChains extends Chains<ProcessingChain> {
- public static final String[] defaultBindings = new String[] {"http://*/processing/*"};
+ public static final BindingPattern[] defaultBindings = new BindingPattern[]{SystemBindingPattern.fromHttpPath("/processing/*")};
public ProcessingChains(AbstractConfigProducer parent, String subId) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/search/GUIHandler.java b/config-model/src/main/java/com/yahoo/vespa/model/container/search/GUIHandler.java
index 1e717f89819..f01bbcd3951 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/search/GUIHandler.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/search/GUIHandler.java
@@ -14,7 +14,7 @@ public class GUIHandler extends Handler<AbstractConfigProducer<?>> {
public static final String BUNDLE = "container-search-gui";
public static final String CLASS = "com.yahoo.search.query.gui.GUIHandler";
- public static final String BINDING = "*/querybuilder/*";
+ public static final String BINDING_PATH = "/querybuilder/*";
public GUIHandler() {
super(new ComponentModel(bundleSpec(CLASS, BUNDLE)));
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 41e092c7ea5..d11e0f9a891 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -29,7 +29,6 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.Zone;
import com.yahoo.search.rendering.RendererRegistry;
import com.yahoo.searchdefinition.derived.RankProfileList;
@@ -57,9 +56,11 @@ import com.yahoo.vespa.model.container.ContainerModel;
import com.yahoo.vespa.model.container.ContainerModelEvaluation;
import com.yahoo.vespa.model.container.IdentityProvider;
import com.yahoo.vespa.model.container.SecretStore;
-import com.yahoo.vespa.model.container.component.Component;
+import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.FileStatusHandlerComponent;
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 com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
@@ -113,7 +114,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private static final String ENVIRONMENT_VARIABLES_ELEMENT = "environment-variables";
static final String SEARCH_HANDLER_CLASS = com.yahoo.search.handler.SearchHandler.class.getName();
- static final String SEARCH_HANDLER_BINDING = "http://*/search/*";
+ static final BindingPattern SEARCH_HANDLER_BINDING = SystemBindingPattern.fromHttpPath("/search/*");
public enum Networking { disable, enable }
@@ -278,8 +279,10 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
String name = "status.html";
Optional<String> statusFile = Optional.ofNullable(System.getenv(HOSTED_VESPA_STATUS_FILE_SETTING));
cluster.addComponent(
- new FileStatusHandlerComponent(name + "-status-handler", statusFile.orElse(HOSTED_VESPA_STATUS_FILE),
- "http://*/" + name));
+ new FileStatusHandlerComponent(
+ name + "-status-handler",
+ statusFile.orElse(HOSTED_VESPA_STATUS_FILE),
+ SystemBindingPattern.fromHttpPath("/" + name)));
} else {
cluster.addVipHandler();
}
@@ -369,7 +372,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
AthenzDomain tenantDomain = deployState.getProperties().athenzDomain().orElse(null);
if (tenantDomain == null) return; // tenant domain not present, cannot add access control. this should eventually be a failure.
AccessControl accessControl =
- new AccessControl.Builder(tenantDomain.value(), deployState.getDeployLogger())
+ new AccessControl.Builder(tenantDomain.value())
.setHandlers(cluster)
.readEnabled(false)
.writeEnabled(false)
@@ -795,8 +798,8 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
ProcessingHandler<SearchChains> searchHandler = new ProcessingHandler<>(cluster.getSearch().getChains(),
"com.yahoo.search.handler.SearchHandler");
- String[] defaultBindings = {SEARCH_HANDLER_BINDING};
- for (String binding: serverBindings(searchElement, defaultBindings)) {
+ BindingPattern[] defaultBindings = {SEARCH_HANDLER_BINDING};
+ for (BindingPattern binding: serverBindings(searchElement, defaultBindings)) {
searchHandler.addServerBindings(binding);
}
@@ -805,12 +808,12 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addGUIHandler(ApplicationContainerCluster cluster) {
Handler<?> guiHandler = new GUIHandler();
- guiHandler.addServerBindings("http://"+GUIHandler.BINDING);
+ guiHandler.addServerBindings(SystemBindingPattern.fromHttpPath(GUIHandler.BINDING_PATH));
cluster.addComponent(guiHandler);
}
- private String[] serverBindings(Element searchElement, String... defaultBindings) {
+ private BindingPattern[] serverBindings(Element searchElement, BindingPattern... defaultBindings) {
List<Element> bindings = XML.getChildren(searchElement, "binding");
if (bindings.isEmpty())
return defaultBindings;
@@ -818,16 +821,16 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
return toBindingList(bindings);
}
- private String[] toBindingList(List<Element> bindingElements) {
- List<String> result = new ArrayList<>();
+ private BindingPattern[] toBindingList(List<Element> bindingElements) {
+ List<BindingPattern> result = new ArrayList<>();
for (Element element: bindingElements) {
String text = element.getTextContent().trim();
if (!text.isEmpty())
- result.add(text);
+ result.add(UserBindingPattern.fromPattern(text));
}
- return result.toArray(new String[result.size()]);
+ return result.toArray(BindingPattern[]::new);
}
private ContainerDocumentApi buildDocumentApi(ApplicationContainerCluster cluster, Element spec) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java
index ae74dbdb4a7..61464799812 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java
@@ -6,19 +6,17 @@ import com.yahoo.vespa.model.clients.ContainerDocumentApi;
import org.w3c.dom.Element;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
/**
* @author Einar M R Rosenvinge
- * @since 5.1.11
*/
public class DocumentApiOptionsBuilder {
private static final Logger log = Logger.getLogger(DocumentApiOptionsBuilder.class.getName());
- private static final String[] DEFAULT_BINDINGS = {"http://*/"};
+
public static ContainerDocumentApi.Options build(Element spec) {
return new ContainerDocumentApi.Options(getBindings(spec));
@@ -27,8 +25,7 @@ public class DocumentApiOptionsBuilder {
private static List<String> getBindings(Element spec) {
Collection<Element> bindingElems = XML.getChildren(spec, "binding");
if (bindingElems.isEmpty())
- return Arrays.asList(DEFAULT_BINDINGS);
-
+ return List.of();
List<String> bindings = new ArrayList<>();
for (Element e :bindingElems) {
String binding = getBinding(e);
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java
new file mode 100644
index 00000000000..cce88bc02f9
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java
@@ -0,0 +1,104 @@
+package com.yahoo.vespa.model.application.validation;// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.yahoo.config.application.api.ApplicationPackage;
+import com.yahoo.config.model.NullConfigModelRegistry;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.model.deploy.TestProperties;
+import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.vespa.model.VespaModel;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+
+/**
+ * @author bjorncs
+ */
+public class UriBindingsValidatorTest {
+
+ @Rule
+ public ExpectedException exceptionRule = ExpectedException.none();
+
+ @Test
+ public void fails_on_user_handler_binding_with_port() throws IOException, SAXException {
+ exceptionRule.expect(IllegalArgumentException.class);
+ exceptionRule.expectMessage("For binding 'http://*:4443/my-handler': binding with port is not allowed");
+ runUriBindingValidator(true, createServicesXmlWithHandler("http://*:4443/my-handler"));
+ }
+
+ @Test
+ public void fails_on_user_handler_binding_with_hostname() throws IOException, SAXException {
+ exceptionRule.expect(IllegalArgumentException.class);
+ exceptionRule.expectMessage("For binding 'http://myhostname/my-handler': only binding with wildcard ('*') for hostname is allowed");
+ runUriBindingValidator(true, createServicesXmlWithHandler("http://myhostname/my-handler"));
+ }
+
+ @Test
+ public void fails_on_user_handler_binding_with_non_http_scheme() throws IOException, SAXException {
+ exceptionRule.expect(IllegalArgumentException.class);
+ exceptionRule.expectMessage("For binding 'ftp://*/my-handler': only 'http' is allowed as scheme");
+ runUriBindingValidator(true, createServicesXmlWithHandler("ftp://*/my-handler"));
+ }
+
+ @Test
+ public void fails_on_invalid_filter_binding() throws IOException, SAXException {
+ exceptionRule.expect(IllegalArgumentException.class);
+ exceptionRule.expectMessage("For binding 'https://*:4443/my-request-filer-chain': binding with port is not allowed");
+ runUriBindingValidator(true, createServicesXmlWithRequestFilterChain("https://*:4443/my-request-filer-chain"));
+ }
+
+ @Test
+ public void allows_valid_user_binding() throws IOException, SAXException {
+ runUriBindingValidator(true, createServicesXmlWithHandler("http://*/my-handler"));
+ }
+
+ @Test
+ public void only_restricts_user_bindings_on_hosted() throws IOException, SAXException {
+ runUriBindingValidator(false, createServicesXmlWithRequestFilterChain("https://*:4443/my-request-filer-chain"));
+ }
+
+ private void runUriBindingValidator(boolean isHosted, String servicesXml) throws IOException, SAXException {
+ ApplicationPackage app = new MockApplicationPackage.Builder()
+ .withServices(servicesXml)
+ .build();
+ DeployState deployState = new DeployState.Builder()
+ .applicationPackage(app)
+ .properties(new TestProperties().setHostedVespa(isHosted))
+ .build();
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+ new UriBindingsValidator().validate(model, deployState);
+ }
+
+ private static String createServicesXmlWithHandler(String handlerBinding) {
+ return String.join(
+ "\n",
+ "<services version='1.0'>",
+ " <container id='default' version='1.0'>",
+ " <handler id='custom.Handler'>",
+ " <binding>" + handlerBinding + "</binding>",
+ " </handler>",
+ " </container>",
+ "</services>");
+ }
+
+ private static String createServicesXmlWithRequestFilterChain(String filterBinding) {
+ return String.join(
+ "\n",
+ "<services version='1.0'>",
+ " <container version='1.0'>",
+ " <http>",
+ " <server port='8080' id='main' />",
+ " <filtering>",
+ " <request-chain id='myChain'>",
+ " <filter id='myFilter'/>",
+ " <binding>" + filterBinding + "</binding>",
+ " </request-chain>",
+ " </filtering>",
+ " </http>",
+ " </container>",
+ "</services>");
+ }
+
+} \ No newline at end of file
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/component/BindingPatternTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/component/BindingPatternTest.java
new file mode 100644
index 00000000000..91a2b65c0e0
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/component/BindingPatternTest.java
@@ -0,0 +1,53 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.component;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * @author bjorncs
+ */
+public class BindingPatternTest {
+
+ @Test
+ public void parses_valid_bindings_correctly() {
+ assertBindingParses("http://host:1234/path");
+ assertBindingParses("http://host/path");
+ assertBindingParses("http://host/");
+ assertBindingParses("*://*:*/*");
+ assertBindingParses("http://*/*");
+ assertBindingParses("https://*/my/path");
+ assertBindingParses("https://*/path/*");
+ assertBindingParses("https://host:*/path/*");
+ assertBindingParses("https://host:1234/*");
+ }
+
+ @Test
+ public void getters_returns_correct_components() {
+ {
+ BindingPattern pattern = SystemBindingPattern.fromPattern("http://host:1234/path/*");
+ assertEquals("http", pattern.scheme());
+ assertEquals("host", pattern.host());
+ assertEquals("1234", pattern.port().get());
+ assertEquals("/path/*", pattern.path());
+ }
+ {
+ BindingPattern pattern = SystemBindingPattern.fromPattern("https://*/path/v1/");
+ assertEquals("https", pattern.scheme());
+ assertEquals("*", pattern.host());
+ assertFalse(pattern.port().isPresent());
+ assertEquals("/path/v1/", pattern.path());
+ }
+ }
+
+ private static void assertBindingParses(String binding) {
+ BindingPattern pattern = SystemBindingPattern.fromPattern(binding);
+ String stringRepresentation = pattern.patternString();
+ assertEquals(
+ "Expected string representation of parsed binding to match original binding string",
+ binding, stringRepresentation);
+ }
+
+} \ No newline at end of file
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/http/FilterBindingsTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/http/FilterBindingsTest.java
index 0f9de516a4b..4ca7590673d 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/http/FilterBindingsTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/http/FilterBindingsTest.java
@@ -1,10 +1,12 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.http;
-import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.jdisc.http.ServerConfig;
import com.yahoo.vespa.model.container.ContainerModel;
+import com.yahoo.vespa.model.container.component.BindingPattern;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.http.xml.HttpBuilder;
import com.yahoo.vespa.model.container.xml.ContainerModelBuilder;
@@ -21,7 +23,7 @@ import static org.junit.Assert.assertNotNull;
*/
public class FilterBindingsTest extends DomBuilderTest {
- private static final String MY_CHAIN_BINDING = "http://*/my-chain-binding";
+ private static final BindingPattern MY_CHAIN_BINDING = UserBindingPattern.fromHttpPath("/my-chain-binding");
private Http buildHttp(Element xml) {
Http http = new HttpBuilder().build(root.getDeployState(), root, xml);
@@ -42,13 +44,13 @@ public class FilterBindingsTest extends DomBuilderTest {
"<http>",
" <filtering>",
" <request-chain id='my-request-chain'>",
- " <binding>" + MY_CHAIN_BINDING + "</binding>",
+ " <binding>" + MY_CHAIN_BINDING.patternString() + "</binding>",
" </request-chain>",
" </filtering>",
"</http>");
Http http = buildHttp(xml);
- Binding binding = first(http.getBindings());
+ FilterBinding binding = first(http.getBindings());
assertEquals("my-request-chain", binding.filterId().getName());
assertEquals(MY_CHAIN_BINDING, binding.binding());
@@ -62,13 +64,13 @@ public class FilterBindingsTest extends DomBuilderTest {
"<http>",
" <filtering>",
" <response-chain id='my-response-chain'>",
- " <binding>" + MY_CHAIN_BINDING + "</binding>",
+ " <binding>" + MY_CHAIN_BINDING.patternString() + "</binding>",
" </response-chain>",
" </filtering>",
"</http>");
Http http = buildHttp(xml);
- Binding binding = first(http.getBindings());
+ FilterBinding binding = first(http.getBindings());
assertEquals("my-response-chain", binding.filterId().getName());
assertEquals(MY_CHAIN_BINDING, binding.binding());
@@ -83,7 +85,7 @@ public class FilterBindingsTest extends DomBuilderTest {
" <http>",
" <filtering>",
" <request-chain id='my-request-chain'>",
- " <binding>" + MY_CHAIN_BINDING + "</binding>",
+ " <binding>" + MY_CHAIN_BINDING.patternString() + "</binding>",
" </request-chain>",
" </filtering>",
" <server id='server1' port='8000' />",
@@ -96,13 +98,13 @@ public class FilterBindingsTest extends DomBuilderTest {
final ServerConfig config = root.getConfig(ServerConfig.class, "container/http/jdisc-jetty/server1");
assertEquals(1, config.filter().size());
assertEquals("my-request-chain", config.filter(0).id());
- assertEquals(MY_CHAIN_BINDING, config.filter(0).binding());
+ assertEquals(MY_CHAIN_BINDING.patternString(), config.filter(0).binding());
}
{
final ServerConfig config = root.getConfig(ServerConfig.class, "container/http/jdisc-jetty/server2");
assertEquals(1, config.filter().size());
assertEquals("my-request-chain", config.filter(0).id());
- assertEquals(MY_CHAIN_BINDING, config.filter(0).binding());
+ assertEquals(MY_CHAIN_BINDING.patternString(), config.filter(0).binding());
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java
index 28e23ce3222..e054698d40b 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java
@@ -1,19 +1,19 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.xml;
-import com.google.common.collect.ImmutableSet;
-import com.yahoo.collections.CollectionUtil;
import com.yahoo.component.ComponentId;
import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
import com.yahoo.config.provision.AthenzDomain;
-import com.yahoo.container.jdisc.state.StateHandler;
import com.yahoo.vespa.model.container.ApplicationContainer;
import com.yahoo.vespa.model.container.ContainerCluster;
+import com.yahoo.vespa.model.container.component.BindingPattern;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
import com.yahoo.vespa.model.container.http.AccessControl;
+import com.yahoo.vespa.model.container.http.FilterBinding;
import com.yahoo.vespa.model.container.http.Http;
-import com.yahoo.vespa.model.container.http.Binding;
import com.yahoo.vespa.model.container.http.xml.HttpBuilder;
import com.yahoo.vespa.model.container.jersey.Jersey2Servlet;
import org.junit.Test;
@@ -41,18 +41,20 @@ import static org.junit.Assert.assertTrue;
*/
public class AccessControlTest extends ContainerModelBuilderTestBase {
- private static final Set<String> REQUIRED_HANDLER_BINDINGS = ImmutableSet.of(
- "/custom-handler/",
- "/search/",
- "/document/",
- ContainerCluster.RESERVED_URI_PREFIX);
-
- private static final Set<String> FORBIDDEN_HANDLER_BINDINGS = ImmutableSet.of(
- "/ApplicationStatus",
- "/status.html",
- "/statistics/",
- StateHandler.STATE_API_ROOT,
- ContainerCluster.ROOT_HANDLER_PATH);
+ private static final Set<BindingPattern> REQUIRED_HANDLER_BINDINGS =
+ Set.of(
+ UserBindingPattern.fromHttpPath("/custom-handler/*"),
+ SystemBindingPattern.fromHttpPath("/search/*"),
+ SystemBindingPattern.fromHttpPath("/document/v1/*"),
+ SystemBindingPattern.fromHttpPath("/reserved-for-internal-use/feedapi"));
+
+ private static final Set<BindingPattern> FORBIDDEN_HANDLER_BINDINGS =
+ Set.of(
+ SystemBindingPattern.fromHttpPath("/ApplicationStatus"),
+ SystemBindingPattern.fromHttpPath("/status.html"),
+ SystemBindingPattern.fromHttpPath("/statistics/"),
+ SystemBindingPattern.fromHttpPath("/state/v1"),
+ SystemBindingPattern.fromHttpPath("/"));
@Test
public void access_control_filter_chain_is_set_up() {
@@ -135,16 +137,15 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
Http http = getHttp(clusterElem);
- Set<String> foundRequiredBindings = REQUIRED_HANDLER_BINDINGS.stream()
+ Set<BindingPattern> foundRequiredBindings = REQUIRED_HANDLER_BINDINGS.stream()
.filter(requiredBinding -> containsBinding(http.getBindings(), requiredBinding))
.collect(Collectors.toSet());
- Set<String> missingRequiredBindings = new HashSet<>(REQUIRED_HANDLER_BINDINGS);
+ Set<BindingPattern> missingRequiredBindings = new HashSet<>(REQUIRED_HANDLER_BINDINGS);
missingRequiredBindings.removeAll(foundRequiredBindings);
- assertTrue("Access control chain was not bound to: " + CollectionUtil.mkString(missingRequiredBindings, ", "),
+ assertTrue("Access control chain was not bound to: " + prettyString(missingRequiredBindings),
missingRequiredBindings.isEmpty());
- FORBIDDEN_HANDLER_BINDINGS.forEach(forbiddenPath -> {
- String forbiddenBinding = String.format("http://*%s", forbiddenPath);
+ FORBIDDEN_HANDLER_BINDINGS.forEach(forbiddenBinding -> {
http.getBindings().forEach(
binding -> assertNotEquals("Access control chain was bound to: " + binding.binding(), binding.binding(), forbiddenBinding));
});
@@ -152,14 +153,14 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
@Test
public void handler_can_be_excluded_by_excluding_one_of_its_bindings() {
- final String notExcludedBinding = "http://*/custom-handler/*";
- final String excludedBinding = "http://*/excluded/*";
+ BindingPattern notExcludedBinding = UserBindingPattern.fromHttpPath("/custom-handler/*");
+ BindingPattern excludedBinding = SystemBindingPattern.fromHttpPath("/excluded/*");
Element clusterElem = DomBuilderTest.parse(
"<container version='1.0'>",
httpWithExcludedBinding(excludedBinding),
" <handler id='custom.Handler'>",
- " <binding>" + notExcludedBinding + "</binding>",
- " <binding>" + excludedBinding + "</binding>",
+ " <binding>" + notExcludedBinding.patternString() + "</binding>",
+ " <binding>" + excludedBinding.patternString() + "</binding>",
" </handler>",
"</container>");
@@ -175,7 +176,6 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
public void access_control_filter_chain_has_all_servlet_bindings() {
final String servletPath = "servlet/path";
final String restApiPath = "api/v0";
- final Set<String> requiredBindings = ImmutableSet.of(servletPath, restApiPath);
Element clusterElem = DomBuilderTest.parse(
"<container version='1.0'>",
" <servlet id='foo' class='bar' bundle='baz'>",
@@ -191,19 +191,22 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
Http http = getHttp(clusterElem);
- Set<String> missingRequiredBindings = requiredBindings.stream()
+ Set<BindingPattern> requiredBindings = Set.of(
+ SystemBindingPattern.fromHttpPath("/" + servletPath),
+ SystemBindingPattern.fromHttpPath("/" + restApiPath + "/*"));
+ Set<BindingPattern> missingRequiredBindings = requiredBindings.stream()
.filter(requiredBinding -> ! containsBinding(http.getBindings(), requiredBinding))
.collect(Collectors.toSet());
- assertTrue("Access control chain was not bound to: " + CollectionUtil.mkString(missingRequiredBindings, ", "),
+ assertTrue("Access control chain was not bound to: " + prettyString(missingRequiredBindings),
missingRequiredBindings.isEmpty());
}
@Test
public void servlet_can_be_excluded_by_excluding_one_of_its_bindings() {
- final String servletPath = "servlet/path";
- final String notExcludedBinding = "http://*:8081/" + servletPath;
- final String excludedBinding = "http://*:8080/" + servletPath;
+ String servletPath = "servlet/path";
+ BindingPattern notExcludedBinding = SystemBindingPattern.fromPattern("http://*:8081/" + servletPath);
+ BindingPattern excludedBinding = SystemBindingPattern.fromPattern("http://*:8080/" + servletPath);
Element clusterElem = DomBuilderTest.parse(
"<container version='1.0'>",
httpWithExcludedBinding(excludedBinding),
@@ -222,9 +225,9 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
@Test
public void rest_api_can_be_excluded_by_excluding_one_of_its_bindings() {
- final String restApiPath = "api/v0";
- final String notExcludedBinding = "http://*:8081/" + restApiPath + Jersey2Servlet.BINDING_SUFFIX;;
- final String excludedBinding = "http://*:8080/" + restApiPath + Jersey2Servlet.BINDING_SUFFIX;;
+ String restApiPath = "api/v0";
+ BindingPattern notExcludedBinding = SystemBindingPattern.fromPattern("http://*:8081/" + restApiPath + Jersey2Servlet.BINDING_SUFFIX);
+ BindingPattern excludedBinding = SystemBindingPattern.fromPattern("http://*:8080/" + restApiPath + Jersey2Servlet.BINDING_SUFFIX);;
Element clusterElem = DomBuilderTest.parse(
"<container version='1.0'>",
httpWithExcludedBinding(excludedBinding),
@@ -290,14 +293,17 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
assertThat(http.getFilterChains().hasChain(ComponentId.fromString("myChain")), is(true));
}
+ private static String prettyString(Set<BindingPattern> missingRequiredBindings) {
+ return missingRequiredBindings.stream().map(BindingPattern::patternString).collect(Collectors.joining(", "));
+ }
- private String httpWithExcludedBinding(String excludedBinding) {
+ private String httpWithExcludedBinding(BindingPattern excludedBinding) {
return joinLines(
" <http>",
" <filtering>",
" <access-control domain='foo'>",
" <exclude>",
- " <binding>" + excludedBinding + "</binding>",
+ " <binding>" + excludedBinding.patternString() + "</binding>",
" </exclude>",
" </access-control>",
" </filtering>",
@@ -312,9 +318,9 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
return http;
}
- private boolean containsBinding(Collection<Binding> bindings, String binding) {
- for (Binding b : bindings) {
- if (b.binding().contains(binding))
+ private boolean containsBinding(Collection<FilterBinding> bindings, BindingPattern binding) {
+ for (FilterBinding b : bindings) {
+ if (b.binding().equals(binding))
return true;
}
return false;
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
index ac2e1b88c0b..73a68429b6d 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
@@ -4,6 +4,8 @@ package com.yahoo.vespa.model.container.xml;
import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
import com.yahoo.vespa.model.container.ContainerCluster;
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.junit.Test;
import org.w3c.dom.Element;
@@ -40,24 +42,21 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa
"<container id='cluster1' version='1.0'>",
" <document-api>",
" <binding>http://*/document-api/</binding>",
- " <binding>missing-trailing-slash</binding>",
" </document-api>",
nodesXml,
"</container>");
createModel(root, elem);
- verifyCustomBindings("com.yahoo.vespa.http.server.FeedHandler", ContainerCluster.RESERVED_URI_PREFIX + "/feedapi");
+ verifyCustomBindings("com.yahoo.vespa.http.server.FeedHandler");
}
- private void verifyCustomBindings(String id, String bindingSuffix) {
+ private void verifyCustomBindings(String id) {
Handler<?> handler = getHandlers("cluster1").get(id);
- assertThat(handler.getServerBindings(), hasItem("http://*/document-api/" + bindingSuffix));
- assertThat(handler.getServerBindings(), hasItem("http://*/document-api/" + bindingSuffix + "/"));
- assertThat(handler.getServerBindings(), hasItem("missing-trailing-slash/" + bindingSuffix));
- assertThat(handler.getServerBindings(), hasItem("missing-trailing-slash/" + bindingSuffix + "/"));
+ assertThat(handler.getServerBindings(), hasItem(UserBindingPattern.fromHttpPath("/document-api/reserved-for-internal-use/feedapi")));
+ assertThat(handler.getServerBindings(), hasItem(UserBindingPattern.fromHttpPath("/document-api/reserved-for-internal-use/feedapi/")));
- assertThat(handler.getServerBindings().size(), is(4));
+ assertThat(handler.getServerBindings().size(), is(2));
}
@Test
@@ -76,8 +75,12 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa
assertThat(handlerMap.get("com.yahoo.container.jdisc.state.StateHandler"), not(nullValue()));
assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler"), not(nullValue()));
- assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings().contains("http://*/" + ContainerCluster.RESERVED_URI_PREFIX + "/feedapi"), is(true));
- assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings().contains("http://*/" + ContainerCluster.RESERVED_URI_PREFIX + "/feedapi/"), is(true));
+ assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings()
+ .contains(SystemBindingPattern.fromHttpPath("/reserved-for-internal-use/feedapi")),
+ is(true));
+ assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings()
+ .contains(SystemBindingPattern.fromHttpPath("/reserved-for-internal-use/feedapi")),
+ is(true));
assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings().size(), equalTo(2));
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
index fdd7ae57f0f..6114449c948 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
@@ -241,7 +241,7 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>" +
" <handler id='userRootHandler'>" +
- " <binding>" + ROOT_HANDLER_BINDING + "</binding>" +
+ " <binding>" + ROOT_HANDLER_BINDING.patternString() + "</binding>" +
" </handler>" +
"</container>");
createModel(root, clusterElem);
@@ -260,7 +260,7 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>" +
" <handler id='userHandler'>" +
- " <binding>" + STATE_HANDLER_BINDING_1 + "</binding>" +
+ " <binding>" + STATE_HANDLER_BINDING_1.patternString() + "</binding>" +
" </handler>" +
"</container>");
try {
@@ -277,9 +277,9 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
createClusterWithJDiscHandler();
String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
assertThat(discBindingsConfig, containsString("{discHandler}"));
- assertThat(discBindingsConfig, containsString(".serverBindings[0] \"binding0\""));
- assertThat(discBindingsConfig, containsString(".serverBindings[1] \"binding1\""));
- assertThat(discBindingsConfig, containsString(".clientBindings[0] \"clientBinding\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[0] \"http://*/binding0\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[1] \"http://*/binding1\""));
+ assertThat(discBindingsConfig, containsString(".clientBindings[0] \"http://*/clientBinding\""));
}
@Test
@@ -292,9 +292,9 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>",
" <handler id='discHandler'>",
- " <binding>binding0</binding>",
- " <binding>binding1</binding>",
- " <clientBinding>clientBinding</clientBinding>",
+ " <binding>http://*/binding0</binding>",
+ " <binding>http://*/binding1</binding>",
+ " <clientBinding>http://*/clientBinding</clientBinding>",
" </handler>",
"</container>");
@@ -340,16 +340,16 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>",
" <processing>",
- " <binding>binding0</binding>",
- " <binding>binding1</binding>",
+ " <binding>http://*/binding0</binding>",
+ " <binding>http://*/binding1</binding>",
" </processing>",
"</container>");
createModel(root, clusterElem);
String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
- assertThat(discBindingsConfig, containsString(".serverBindings[0] \"binding0\""));
- assertThat(discBindingsConfig, containsString(".serverBindings[1] \"binding1\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[0] \"http://*/binding0\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[1] \"http://*/binding1\""));
assertThat(discBindingsConfig, not(containsString("/processing/*")));
}
@@ -358,9 +358,9 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
createModelWithClientProvider();
String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
assertThat(discBindingsConfig, containsString("{discClient}"));
- assertThat(discBindingsConfig, containsString(".clientBindings[0] \"binding0\""));
- assertThat(discBindingsConfig, containsString(".clientBindings[1] \"binding1\""));
- assertThat(discBindingsConfig, containsString(".serverBindings[0] \"serverBinding\""));
+ assertThat(discBindingsConfig, containsString(".clientBindings[0] \"http://*/binding0\""));
+ assertThat(discBindingsConfig, containsString(".clientBindings[1] \"http://*/binding1\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[0] \"http://*/serverBinding\""));
}
@Test
@@ -373,9 +373,9 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>" +
" <client id='discClient'>" +
- " <binding>binding0</binding>" +
- " <binding>binding1</binding>" +
- " <serverBinding>serverBinding</serverBinding>" +
+ " <binding>http://*/binding0</binding>" +
+ " <binding>http://*/binding1</binding>" +
+ " <serverBinding>http://*/serverBinding</serverBinding>" +
" </client>" +
"</container>" );
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
index b2f9c805be1..c8564c5a273 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
@@ -20,6 +20,8 @@ import static com.yahoo.test.Matchers.hasItemWithMethod;
import static com.yahoo.vespa.model.container.search.ContainerSearch.QUERY_PROFILE_REGISTRY_CLASS;
import static com.yahoo.vespa.model.container.xml.ContainerModelBuilder.SEARCH_HANDLER_BINDING;
import static com.yahoo.vespa.model.container.xml.ContainerModelBuilder.SEARCH_HANDLER_CLASS;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -48,7 +50,7 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
createModel(root, clusterElem);
String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
- assertTrue(discBindingsConfig.contains(GUIHandler.BINDING));
+ assertThat(discBindingsConfig, containsString(GUIHandler.BINDING_PATH));
ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
@@ -66,8 +68,8 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
Element clusterElem = DomBuilderTest.parse(
"<container id='default' version='1.0'>",
" <search>",
- " <binding>binding0</binding>",
- " <binding>binding1</binding>",
+ " <binding>http://*/binding0</binding>",
+ " <binding>http://*/binding1</binding>",
" </search>",
nodesXml,
"</container>");
@@ -75,9 +77,9 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
createModel(root, clusterElem);
String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
- assertTrue(discBindingsConfig.contains(".serverBindings[0] \"binding0\""));
- assertTrue(discBindingsConfig.contains(".serverBindings[1] \"binding1\""));
- assertFalse(discBindingsConfig.contains("/search/*"));
+ assertThat(discBindingsConfig, containsString(".serverBindings[0] \"http://*/binding0\""));
+ assertThat(discBindingsConfig, containsString(".serverBindings[1] \"http://*/binding1\""));
+ assertThat(discBindingsConfig, not(containsString("/search/*")));
}
@Test
@@ -103,7 +105,7 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
"<container id='default' version='1.0'>",
" <search />",
" <handler id='" + myHandler + "'>",
- " <binding>" + SEARCH_HANDLER_BINDING + "</binding>",
+ " <binding>" + SEARCH_HANDLER_BINDING.patternString() + "</binding>",
" </handler>",
nodesXml,
"</container>");
@@ -111,7 +113,7 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
createModel(root, clusterElem);
var discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default");
- assertEquals(SEARCH_HANDLER_BINDING, discBindingsConfig.handlers(myHandler).serverBindings(0));
+ assertEquals(SEARCH_HANDLER_BINDING.patternString(), discBindingsConfig.handlers(myHandler).serverBindings(0));
assertNull(discBindingsConfig.handlers(SEARCH_HANDLER_CLASS));
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java
index 8a0f24bcd48..3a8d80e5ffe 100644
--- a/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java
+++ b/config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java
@@ -43,11 +43,11 @@ import java.util.concurrent.ThreadLocalRandom;
public class LoadTester {
private static boolean debug = false;
- private Transport transport = new Transport("rpc-client");
+ private final Transport transport = new Transport("rpc-client");
protected Supervisor supervisor = new Supervisor(transport);
private List<ConfigKey<?>> configs = new ArrayList<>();
private Map<ConfigDefinitionKey, Tuple2<String, String[]>> defs = new HashMap<>();
- private CompressionType compressionType = JRTConfigRequestFactory.getCompressionType();
+ private final CompressionType compressionType = JRTConfigRequestFactory.getCompressionType();
/**
* @param args command-line arguments
@@ -149,7 +149,7 @@ public class LoadTester {
return ret;
}
- private class Metrics {
+ private static class Metrics {
long totBytes = 0;
long totLatency = 0;
@@ -214,9 +214,7 @@ public class LoadTester {
Tuple2<String, String[]> defContent = defs.get(dKey);
if (defContent == null && defs.size() > 0) { // Only complain if we actually did run with a def dir
System.out.println("# No def found for " + dKey + ", not sending in request.");
- }/* else {
- System.out.println("# FOUND: "+dKey+" : "+ StringUtilities.implode(defContent, "\n"));
- }*/
+ }
request = getRequest(ConfigKey.createFull(reqKey.getName(), reqKey.getConfigId(), reqKey.getNamespace(), defContent.first), defContent.second);
if (debug) System.out.println("# Requesting: " + reqKey);
long start = System.currentTimeMillis();
@@ -261,7 +259,7 @@ public class LoadTester {
if (defContent == null) defContent = new String[0];
final long serverTimeout = 1000;
return JRTClientConfigRequestV3.createWithParams(reqKey, DefContent.fromList(Arrays.asList(defContent)),
- "unknown", "", 0, serverTimeout, Trace.createDummy(),
+ ConfigUtils.getCanonicalHostName(), "", 0, serverTimeout, Trace.createDummy(),
compressionType, Optional.empty());
}
@@ -269,4 +267,5 @@ public class LoadTester {
return supervisor.connect(spec);
}
}
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
index 03769d0a537..b38d90d470f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
@@ -47,7 +47,6 @@ import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -317,8 +316,7 @@ public class SessionRepository {
getRemoteSessions().forEach(this::sessionAdded);
}
- private synchronized void sessionsChanged() throws NumberFormatException {
- List<Long> sessions = getSessionListFromDirectoryCache(directoryCache.getCurrentData());
+ private synchronized void sessionsChanged(List<Long> sessions) throws NumberFormatException {
checkForRemovedSessions(sessions);
checkForAddedSessions(sessions);
}
@@ -418,14 +416,15 @@ public class SessionRepository {
private void childEvent(CuratorFramework ignored, PathChildrenCacheEvent event) {
zkWatcherExecutor.execute(() -> {
log.log(Level.FINE, () -> "Got child event: " + event);
+ List<Long> sessions = getSessionListFromDirectoryCache(directoryCache.getCurrentData());
switch (event.getType()) {
case CHILD_ADDED:
- sessionsChanged();
- synchronizeOnNew(getSessionListFromDirectoryCache(Collections.singletonList(event.getData())));
+ sessionsChanged(sessions);
+ synchronizeOnNew(sessions);
break;
case CHILD_REMOVED:
case CONNECTION_RECONNECTED:
- sessionsChanged();
+ sessionsChanged(sessions);
break;
}
});
diff --git a/default_build_settings.cmake b/default_build_settings.cmake
index 5ba7494d1e1..69a69dc1860 100644
--- a/default_build_settings.cmake
+++ b/default_build_settings.cmake
@@ -43,7 +43,7 @@ function(setup_vespa_default_build_settings_darwin)
else()
set(DEFAULT_VESPA_LLVM_VERSION "10" PARENT_SCOPE)
endif()
- set(DEFAULT_CMAKE_PREFIX_PATH "${VESPA_DEPS}" "/usr/local/opt/bison" "/usr/local/opt/flex" "/usr/local/opt/openssl@1.1" "/usr/local/opt/openblas" PARENT_SCOPE)
+ set(DEFAULT_CMAKE_PREFIX_PATH "${VESPA_DEPS}" "/usr/local/opt/bison" "/usr/local/opt/flex" "/usr/local/opt/openssl@1.1" "/usr/local/opt/openblas" "/usr/local/opt/icu4c" PARENT_SCOPE)
set(DEFAULT_EXTRA_LINK_DIRECTORY "${VESPA_DEPS}/lib" "/usr/local/opt/bison/lib" "/usr/local/opt/flex/lib" "/usr/local/opt/icu4c/lib" "/usr/local/opt/openssl@1.1/lib" "/usr/local/opt/openblas/lib")
if(DEFINED DEFAULT_LLVM_LINK_DIRECTORY)
list(APPEND DEFAULT_EXTRA_LINK_DIRECTORY "${DEFAULT_LLVM_LINK_DIRECTORY}")
@@ -278,8 +278,8 @@ function(vespa_use_default_cxx_compiler)
unset(DEFAULT_CMAKE_CXX_COMPILER)
if(NOT DEFINED VESPA_COMPILER_VARIANT OR VESPA_COMPILER_VARIANT STREQUAL "gcc")
if(APPLE)
- set(DEFAULT_CMAKE_C_COMPILER "/usr/local/bin/gcc-9")
- set(DEFAULT_CMAKE_CXX_COMPILER "/usr/local/bin/g++-9")
+ set(DEFAULT_CMAKE_C_COMPILER "/usr/local/bin/gcc-10")
+ set(DEFAULT_CMAKE_CXX_COMPILER "/usr/local/bin/g++-10")
endif()
elseif(VESPA_COMPILER_VARIANT STREQUAL "clang")
if(APPLE)
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseTest.java
index 44026f835dd..149510bdc97 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseTest.java
@@ -149,7 +149,6 @@ public class CuratorDatabaseTest {
this.task = task;
}
- @SuppressWarnings("deprecation")
@Override
public org.apache.curator.framework.api.transaction.CuratorTransaction and(org.apache.curator.framework.api.transaction.CuratorTransaction transaction) {
task.run();
diff --git a/parent/pom.xml b/parent/pom.xml
index 0cfe87c6488..a9998af3962 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -82,12 +82,6 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven-bundle-plugin.version}</version>
- <configuration>
- <!-- TODO: remove when bundle-plugin understands java 10, https://issues.apache.org/jira/browse/FELIX-5879 -->
- <instructions>
- <_noee>true</_noee>
- </instructions>
- </configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -763,14 +757,15 @@
zkfacade/src/main/java/org/apache/curator/**/package-info.java
using something like
find zkfacade/src/main/java/org/apache/curator -name package-info.java | \
- xargs perl -pi -e 's/major = [0-9]+, minor = [0-9]+, micro = [0-9]+/major = 4, minor = 3, micro = 0/g'
+ xargs perl -pi -e 's/major = [0-9]+, minor = [0-9]+, micro = [0-9]+/major = 2, minor = 9, micro = 1/g'
-->
- <curator.version>4.3.0</curator.version>
+ <curator.version>2.13.0</curator.version>
<jna.version>4.5.2</jna.version>
<commons.math3.version>3.6.1</commons.math3.version>
<junit.version>5.6.2</junit.version>
<maven-assembly-plugin.version>3.1.1</maven-assembly-plugin.version>
- <maven-bundle-plugin.version>3.5.0</maven-bundle-plugin.version>
+ <!-- TODO: in order to upgrade above 4.1.0, we probably need to convert fat-model-deps to a jar artifact. -->
+ <maven-bundle-plugin.version>4.1.0</maven-bundle-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
<maven-deploy-plugin.version>2.8.1</maven-deploy-plugin.version>
diff --git a/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp b/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp
index 031dd4f35e7..952c359b716 100644
--- a/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp
@@ -261,6 +261,7 @@ DocumentRetriever::getPartialDocument(search::DocumentIdT lid, const document::D
case FieldSet::Type::DOCID:
break;
}
+ doc->setRepo(getDocumentTypeRepo());
}
return doc;
}
diff --git a/searchlib/src/tests/common/location/geo_location_test.cpp b/searchlib/src/tests/common/location/geo_location_test.cpp
index 31b844d0fc8..eec2411f2af 100644
--- a/searchlib/src/tests/common/location/geo_location_test.cpp
+++ b/searchlib/src/tests/common/location/geo_location_test.cpp
@@ -4,6 +4,7 @@
#include <vespa/searchlib/common/geo_location.h>
#include <vespa/searchlib/common/geo_location_spec.h>
#include <vespa/searchlib/common/geo_location_parser.h>
+#include <vespa/searchlib/query/tree/location.h>
#include <vespa/vespalib/gtest/gtest.h>
using search::common::GeoLocation;
@@ -16,19 +17,36 @@ using Aspect = search::common::GeoLocation::Aspect;
constexpr int32_t plus_inf = std::numeric_limits<int32_t>::max();
constexpr int32_t minus_inf = std::numeric_limits<int32_t>::min();
-constexpr uint32_t u32_inf = std::numeric_limits<uint32_t>::max();
bool is_parseable(const char *str) {
GeoLocationParser parser;
return parser.parseOldFormat(str);
}
+bool is_parseable_new(const char *str, bool with_field = false) {
+ GeoLocationParser parser;
+ if (with_field) {
+ return parser.parseWithField(str);
+ }
+ return parser.parseNoField(str);
+}
+
GeoLocation parse(const char *str) {
GeoLocationParser parser;
EXPECT_TRUE(parser.parseOldFormat(str));
return parser.getGeoLocation();
}
+GeoLocation parse_new(const std::string &str, bool with_field = false) {
+ GeoLocationParser parser;
+ if (with_field) {
+ EXPECT_TRUE(parser.parseWithField(str));
+ } else {
+ EXPECT_TRUE(parser.parseNoField(str));
+ }
+ return parser.getGeoLocation();
+}
+
TEST(GeoLocationParserTest, malformed_bounding_boxes_are_not_parseable) {
EXPECT_TRUE(is_parseable("[2,10,20,30,40]"));
EXPECT_FALSE(is_parseable("[2,10,20,30,40][2,10,20,30,40]"));
@@ -40,6 +58,15 @@ TEST(GeoLocationParserTest, malformed_bounding_boxes_are_not_parseable) {
EXPECT_FALSE(is_parseable("[10,20,30,40]"));
}
+TEST(GeoLocationParserTest, new_bounding_box_formats) {
+ EXPECT_TRUE(is_parseable_new("{b:{x:[10,30],y:[20,40]}}"));
+ EXPECT_TRUE(is_parseable_new("{b:{}}"));
+ EXPECT_TRUE(is_parseable_new("{b:[]}"));
+ EXPECT_TRUE(is_parseable_new("{b:10,b:20}"));
+ EXPECT_TRUE(is_parseable_new("{b:[10, 20, 30, 40]}"));
+ EXPECT_FALSE(is_parseable_new("{b:{x:[10,30],y:[20,40]}"));
+}
+
TEST(GeoLocationParserTest, malformed_circles_are_not_parseable) {
EXPECT_TRUE(is_parseable("(2,10,20,5,0,0,0)"));
EXPECT_FALSE(is_parseable("(2,10,20,5,0,0,0)(2,10,20,5,0,0,0)"));
@@ -52,94 +79,147 @@ TEST(GeoLocationParserTest, malformed_circles_are_not_parseable) {
EXPECT_FALSE(is_parseable("(10,20,5)"));
}
+TEST(GeoLocationParserTest, new_circle_formats) {
+ EXPECT_TRUE(is_parseable_new("{p:{x:10,y:20}}"));
+ EXPECT_TRUE(is_parseable_new("{p:{x:10,y:20},r:5}"));
+ EXPECT_TRUE(is_parseable_new("{p:{x:10, y:10}, r:5}"));
+ EXPECT_TRUE(is_parseable_new("{'p':{y:20,x:10},'r':5}"));
+ EXPECT_TRUE(is_parseable_new("{\n \"p\": { \"x\": 10, \"y\": 20},\n \"r\": 5\n}"));
+ // json demands colon:
+ EXPECT_FALSE(is_parseable_new("{p:{x:10,y:10},r=5}"));
+ // missing y -> 0 default:
+ EXPECT_TRUE(is_parseable_new("{p:{x:10},r:5}"));
+ // unused extra fields are ignored:
+ EXPECT_TRUE(is_parseable_new("{p:{x:10,y:10,z:10},r:5,c:1,d:17}"));
+}
+
TEST(GeoLocationParserTest, bounding_boxes_can_be_parsed) {
- auto loc = parse("[2,10,20,30,40]");
- EXPECT_EQ(false, loc.has_point);
- EXPECT_EQ(true, loc.bounding_box.active());
- EXPECT_EQ(0u, loc.x_aspect.multiplier);
- EXPECT_EQ(0, loc.point.x);
- EXPECT_EQ(0, loc.point.y);
- EXPECT_EQ(std::numeric_limits<uint32_t>::max(), loc.radius);
- EXPECT_EQ(10, loc.bounding_box.x.low);
- EXPECT_EQ(20, loc.bounding_box.y.low);
- EXPECT_EQ(30, loc.bounding_box.x.high);
- EXPECT_EQ(40, loc.bounding_box.y.high);
+ for (const auto & loc : {
+ parse("[2,10,20,30,40]"),
+ parse_new("{b:{x:[10,30],y:[20,40]}}")
+ }) {
+ EXPECT_EQ(false, loc.has_point);
+ EXPECT_EQ(true, loc.bounding_box.active());
+ EXPECT_EQ(0u, loc.x_aspect.multiplier);
+ EXPECT_EQ(0, loc.point.x);
+ EXPECT_EQ(0, loc.point.y);
+ EXPECT_EQ(std::numeric_limits<uint32_t>::max(), loc.radius);
+ EXPECT_EQ(10, loc.bounding_box.x.low);
+ EXPECT_EQ(20, loc.bounding_box.y.low);
+ EXPECT_EQ(30, loc.bounding_box.x.high);
+ EXPECT_EQ(40, loc.bounding_box.y.high);
+ }
}
TEST(GeoLocationParserTest, circles_can_be_parsed) {
- auto loc = parse("(2,10,20,5,0,0,0)");
- EXPECT_EQ(true, loc.has_point);
- EXPECT_EQ(true, loc.bounding_box.active());
- EXPECT_EQ(0u, loc.x_aspect.multiplier);
- EXPECT_EQ(10, loc.point.x);
- EXPECT_EQ(20, loc.point.y);
- EXPECT_EQ(5u, loc.radius);
- EXPECT_EQ(5, loc.bounding_box.x.low);
- EXPECT_EQ(15, loc.bounding_box.y.low);
- EXPECT_EQ(15, loc.bounding_box.x.high);
- EXPECT_EQ(25, loc.bounding_box.y.high);
+ for (const auto & loc : {
+ parse("(2,10,20,5,0,0,0)"),
+ parse_new("{p:{x:10,y:20},r:5}")
+ }) {
+ EXPECT_EQ(true, loc.has_point);
+ EXPECT_EQ(true, loc.bounding_box.active());
+ EXPECT_EQ(0u, loc.x_aspect.multiplier);
+ EXPECT_EQ(10, loc.point.x);
+ EXPECT_EQ(20, loc.point.y);
+ EXPECT_EQ(5u, loc.radius);
+ EXPECT_EQ(5, loc.bounding_box.x.low);
+ EXPECT_EQ(15, loc.bounding_box.y.low);
+ EXPECT_EQ(15, loc.bounding_box.x.high);
+ EXPECT_EQ(25, loc.bounding_box.y.high);
+ }
}
TEST(GeoLocationParserTest, circles_can_have_aspect_ratio) {
- auto loc = parse("(2,10,20,5,0,0,0,2147483648)");
- EXPECT_EQ(true, loc.has_point);
- EXPECT_EQ(true, loc.bounding_box.active());
- EXPECT_EQ(2147483648u, loc.x_aspect.multiplier);
- EXPECT_EQ(10, loc.point.x);
- EXPECT_EQ(20, loc.point.y);
- EXPECT_EQ(5u, loc.radius);
- EXPECT_EQ(-1, loc.bounding_box.x.low);
- EXPECT_EQ(15, loc.bounding_box.y.low);
- EXPECT_EQ(21, loc.bounding_box.x.high);
- EXPECT_EQ(25, loc.bounding_box.y.high);
+ for (const auto & loc : {
+ parse("(2,10,20,5,0,0,0,2147483648)"),
+ parse_new("{p:{x:10,y:20},r:5,a:2147483648}")
+ }) {
+ EXPECT_EQ(true, loc.has_point);
+ EXPECT_EQ(true, loc.bounding_box.active());
+ EXPECT_EQ(2147483648u, loc.x_aspect.multiplier);
+ EXPECT_EQ(10, loc.point.x);
+ EXPECT_EQ(20, loc.point.y);
+ EXPECT_EQ(5u, loc.radius);
+ EXPECT_EQ(-1, loc.bounding_box.x.low);
+ EXPECT_EQ(15, loc.bounding_box.y.low);
+ EXPECT_EQ(21, loc.bounding_box.x.high);
+ EXPECT_EQ(25, loc.bounding_box.y.high);
+ }
+ auto loc2 = parse_new("{p:{x:10,y:10},a:3123456789}");
+ EXPECT_EQ(3123456789, loc2.x_aspect.multiplier);
}
TEST(GeoLocationParserTest, bounding_box_can_be_specified_after_circle) {
- auto loc = parse("(2,10,20,5,0,0,0)[2,10,20,30,40]");
- EXPECT_EQ(true, loc.has_point);
- EXPECT_EQ(true, loc.bounding_box.active());
- EXPECT_EQ(0u, loc.x_aspect.multiplier);
- EXPECT_EQ(10, loc.point.x);
- EXPECT_EQ(20, loc.point.y);
- EXPECT_EQ(5u, loc.radius);
- EXPECT_EQ(10, loc.bounding_box.x.low);
- EXPECT_EQ(20, loc.bounding_box.y.low);
- EXPECT_EQ(15, loc.bounding_box.x.high);
- EXPECT_EQ(25, loc.bounding_box.y.high);
+ for (const auto & loc : {
+ parse("(2,10,20,5,0,0,0)[2,10,20,30,40]"),
+ parse_new("{p:{x:10,y:20},r:5,b:{x:[10,30],y:[20,40]}}")
+ }) {
+ EXPECT_EQ(true, loc.has_point);
+ EXPECT_EQ(true, loc.bounding_box.active());
+ EXPECT_EQ(0u, loc.x_aspect.multiplier);
+ EXPECT_EQ(10, loc.point.x);
+ EXPECT_EQ(20, loc.point.y);
+ EXPECT_EQ(5u, loc.radius);
+ EXPECT_EQ(10, loc.bounding_box.x.low);
+ EXPECT_EQ(20, loc.bounding_box.y.low);
+ EXPECT_EQ(15, loc.bounding_box.x.high);
+ EXPECT_EQ(25, loc.bounding_box.y.high);
+ }
}
TEST(GeoLocationParserTest, circles_can_be_specified_after_bounding_box) {
- auto loc = parse("[2,10,20,30,40](2,10,20,5,0,0,0)");
+ for (const auto & loc : {
+ parse("[2,10,20,30,40](2,10,20,5,0,0,0)"),
+ parse_new("{b:{x:[10,30],y:[20,40]},p:{x:10,y:20},r:5}")
+ }) {
+ EXPECT_EQ(true, loc.has_point);
+ EXPECT_EQ(true, loc.bounding_box.active());
+ EXPECT_EQ(0u, loc.x_aspect.multiplier);
+ EXPECT_EQ(10, loc.point.x);
+ EXPECT_EQ(20, loc.point.y);
+ EXPECT_EQ(5u, loc.radius);
+ EXPECT_EQ(10, loc.bounding_box.x.low);
+ EXPECT_EQ(20, loc.bounding_box.y.low);
+ EXPECT_EQ(15, loc.bounding_box.x.high);
+ EXPECT_EQ(25, loc.bounding_box.y.high);
+ }
+ const auto &loc = parse_new("{a:12345,b:{x:[8,10],y:[8,10]},p:{x:10,y:10},r:3}");
EXPECT_EQ(true, loc.has_point);
- EXPECT_EQ(true, loc.bounding_box.active());
- EXPECT_EQ(0u, loc.x_aspect.multiplier);
EXPECT_EQ(10, loc.point.x);
- EXPECT_EQ(20, loc.point.y);
- EXPECT_EQ(5u, loc.radius);
- EXPECT_EQ(10, loc.bounding_box.x.low);
- EXPECT_EQ(20, loc.bounding_box.y.low);
- EXPECT_EQ(15, loc.bounding_box.x.high);
- EXPECT_EQ(25, loc.bounding_box.y.high);
+ EXPECT_EQ(10, loc.point.y);
+ EXPECT_EQ(12345u, loc.x_aspect.multiplier);
}
TEST(GeoLocationParserTest, santa_search_gives_non_wrapped_bounding_box) {
- auto loc = parse("(2,122163600,89998536,290112,4,2000,0,109704)");
- EXPECT_GE(loc.bounding_box.x.high, loc.bounding_box.x.low);
- EXPECT_GE(loc.bounding_box.y.high, loc.bounding_box.y.low);
+ for (const auto & loc : {
+ parse("(2,122163600,89998536,290112,4,2000,0,109704)"),
+ parse_new("{p:{x:122163600,y:89998536},r:290112,a:109704}")
+ }) {
+ EXPECT_GE(loc.bounding_box.x.high, loc.bounding_box.x.low);
+ EXPECT_GE(loc.bounding_box.y.high, loc.bounding_box.y.low);
+ }
}
TEST(GeoLocationParserTest, near_boundary_search_gives_non_wrapped_bounding_box) {
- auto loc1 = parse("(2,2000000000,2000000000,3000000000,0,1,0)");
- EXPECT_GE(loc1.bounding_box.x.high, loc1.bounding_box.x.low);
- EXPECT_GE(loc1.bounding_box.y.high, loc1.bounding_box.y.low);
- EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high);
- EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high);
-
- auto loc2 = parse("(2,-2000000000,-2000000000,3000000000,0,1,0)");
- EXPECT_GE(loc2.bounding_box.x.high, loc2.bounding_box.x.low);
- EXPECT_GE(loc2.bounding_box.y.high, loc2.bounding_box.y.low);
- EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.x.low);
- EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.y.low);
+ for (const auto & loc1 : {
+ parse("(2,2000000000,2000000000,3000000000,0,1,0)"),
+ parse_new("{p:{x:2000000000,y:2000000000},r:3000000000}")
+ }) {
+ EXPECT_GE(loc1.bounding_box.x.high, loc1.bounding_box.x.low);
+ EXPECT_GE(loc1.bounding_box.y.high, loc1.bounding_box.y.low);
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high);
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), loc1.bounding_box.y.high);
+ }
+
+ for (const auto & loc2 : {
+ parse("(2,-2000000000,-2000000000,3000000000,0,1,0)"),
+ parse_new("{p:{x:-2000000000,y:-2000000000},r:3000000000}")
+ }) {
+ EXPECT_GE(loc2.bounding_box.x.high, loc2.bounding_box.x.low);
+ EXPECT_GE(loc2.bounding_box.y.high, loc2.bounding_box.y.low);
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.x.low);
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), loc2.bounding_box.y.low);
+ }
}
void check_box(const GeoLocation &location, Box expected)
@@ -391,4 +471,67 @@ TEST(GeoLocationTest, box_point_radius_and_aspect) {
EXPECT_EQ(location.bounding_box.y.high, 700);
}
+TEST(GeoLocationParserTest, can_parse_what_query_tree_produces) {
+ search::query::Point point_1{-17, 42};
+ uint32_t distance = 12345;
+ uint32_t aspect_ratio = 67890;
+ search::query::Rectangle rectangle_1(-1, -2, 3, 4);
+
+ search::query::Location loc_1(point_1);
+ std::string str_1 = loc_1.getJsonFormatString();
+ auto result_1 = parse_new(str_1);
+
+ EXPECT_EQ(true, result_1.has_point);
+ EXPECT_EQ(false, result_1.has_radius());
+ EXPECT_EQ(false, result_1.x_aspect.active());
+ EXPECT_EQ(false, result_1.bounding_box.active());
+ EXPECT_EQ(-17, result_1.point.x);
+ EXPECT_EQ(42, result_1.point.y);
+
+ search::query::Location loc_1b(point_1, distance, aspect_ratio);
+ std::string str_1b = loc_1b.getJsonFormatString();
+ auto result_1b = parse_new(str_1b);
+
+ EXPECT_EQ(true, result_1b.has_point);
+ EXPECT_EQ(true, result_1b.has_radius());
+ EXPECT_EQ(true, result_1b.x_aspect.active());
+ EXPECT_EQ(true, result_1b.bounding_box.active());
+ EXPECT_EQ(-17, result_1b.point.x);
+ EXPECT_EQ(42, result_1b.point.y);
+ EXPECT_EQ(distance, result_1b.radius);
+ EXPECT_EQ(aspect_ratio, result_1b.x_aspect.multiplier);
+ EXPECT_EQ(42-distance, result_1b.bounding_box.y.low);
+ EXPECT_EQ(42+distance, result_1b.bounding_box.y.high);
+
+ search::query::Location loc_2(rectangle_1);
+ std::string str_2 = loc_2.getJsonFormatString();
+ auto result_2 = parse_new(str_2);
+
+ EXPECT_EQ(false, result_2.has_point);
+ EXPECT_EQ(false, result_2.has_radius());
+ EXPECT_EQ(false, result_2.x_aspect.active());
+ EXPECT_EQ(true, result_2.bounding_box.active());
+ EXPECT_EQ(-1, result_2.bounding_box.x.low);
+ EXPECT_EQ(-2, result_2.bounding_box.y.low);
+ EXPECT_EQ(3, result_2.bounding_box.x.high);
+ EXPECT_EQ(4, result_2.bounding_box.y.high);
+
+ search::query::Location loc_3(rectangle_1, point_1, distance, aspect_ratio);
+ std::string str_3 = loc_3.getJsonFormatString();
+ auto result_3 = parse_new(str_3);
+
+ EXPECT_EQ(true, result_3.has_point);
+ EXPECT_EQ(true, result_3.has_radius());
+ EXPECT_EQ(true, result_3.x_aspect.active());
+ EXPECT_EQ(true, result_3.bounding_box.active());
+ EXPECT_EQ(-17, result_3.point.x);
+ EXPECT_EQ(42, result_3.point.y);
+ EXPECT_EQ(distance, result_3.radius);
+ EXPECT_EQ(aspect_ratio, result_3.x_aspect.multiplier);
+ EXPECT_EQ(-1, result_3.bounding_box.x.low);
+ EXPECT_EQ(-2, result_3.bounding_box.y.low);
+ EXPECT_EQ(3, result_3.bounding_box.x.high);
+ EXPECT_EQ(4, result_3.bounding_box.y.high);
+}
+
GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
index 032caaacba8..b9e4bf565ef 100644
--- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
+++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp
@@ -263,8 +263,18 @@ public:
const common::Location &location() const { return _location; }
SearchIterator::UP
- createLeafSearch(const TermFieldMatchDataArray &, bool strict) const override
+ createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override
{
+ if (tfmda.size() == 1) {
+ // search in exactly one field
+ fef::TermFieldMatchData &tfmd = *tfmda[0];
+ return search::common::create_location_iterator(tfmd,
+ _attribute.getNumDocs(),
+ strict,
+ _location);
+ } else {
+ LOG(debug, "wrong size tfmda: %zu (fallback to old location iterator)\n", tfmda.size());
+ }
return FastS_AllocLocationIterator(_attribute.getNumDocs(), strict, _location);
}
};
@@ -273,7 +283,8 @@ public:
Blueprint::UP
make_location_blueprint(const FieldSpec &field, const IAttributeVector &attribute, const Location &loc) {
- LOG(debug, "make_location_blueprint(p[%d,%d], r[%u], aspect[%u], bb[[%d,%d],[%d,%d]])",
+ LOG(debug, "make_location_blueprint(fieldId[%u], p[%d,%d], r[%u], aspect[%u], bb[[%d,%d],[%d,%d]])",
+ field.getFieldId(),
loc.point.x, loc.point.y, loc.radius,
loc.x_aspect.multiplier,
loc.bounding_box.x.low, loc.bounding_box.x.high,
diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
index 05c53348699..53792e56562 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
+++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.cpp
@@ -3,6 +3,11 @@
#include "geo_location_parser.h"
#include <limits>
#include <vespa/vespalib/stllike/asciistream.h>
+#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/data/slime/json_format.h>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".searchlib.common.geo_location_parser");
namespace {
@@ -39,7 +44,7 @@ GeoLocationParser::GeoLocationParser()
_max_x(std::numeric_limits<int32_t>::max()),
_min_y(std::numeric_limits<int32_t>::min()),
_max_y(std::numeric_limits<int32_t>::max()),
- _parseError(NULL)
+ _parseError(nullptr)
{}
bool
@@ -62,7 +67,7 @@ GeoLocationParser::parseOldFormatWithField(const std::string &str)
{
auto sep = str.find(':');
if (sep == std::string::npos) {
- _parseError = "Location string lacks field specification.";
+ _parseError = "Location string lacks field specification";
return false;
}
_field_name = str.substr(0, sep);
@@ -179,9 +184,87 @@ GeoLocationParser::parseOldFormat(const std::string &locStr)
return _valid;
}
+bool
+GeoLocationParser::parseWithField(const std::string &str)
+{
+ auto sep = str.find(':');
+ if (sep == std::string::npos) {
+ _parseError = "Location string lacks field specification";
+ return false;
+ }
+ _field_name = str.substr(0, sep);
+ std::string only_loc = str.substr(sep + 1);
+ return parseNoField(only_loc);
+}
+
+bool
+GeoLocationParser::parseNoField(const std::string &str)
+{
+ if (str.empty()) {
+ _parseError = "Location string is empty";
+ return false;
+ }
+ if (str[0] == '(' || str[0] == '[') {
+ return parseOldFormat(str);
+ }
+ if (str[0] != '{') {
+ _parseError = "Location string should start with '{'";
+ return false;
+ }
+ return parseJsonFormat(str);
+}
+
+bool
+GeoLocationParser::parseJsonFormat(const std::string &str)
+{
+ vespalib::Slime slime;
+ size_t decoded = vespalib::slime::JsonFormat::decode(str, slime);
+ if (decoded == 0) {
+ LOG(warning, "bad location JSON: %s\n>> %s <<",
+ slime.get()["error_message"].asString().make_string().c_str(),
+ str.c_str());
+ _parseError = "Failed decoding JSON format location";
+ return false;
+ }
+ // fprintf(stderr, "parsed location JSON %s -> %s\n", str.c_str(), slime.toString().c_str());
+ const auto &root = slime.get();
+ const auto &point = root["p"];
+ const auto &radius = root["r"];
+ const auto &aspect = root["a"];
+ const auto &bbox = root["b"];
+
+ if (point.valid()) {
+ _x = point["x"].asLong();
+ _y = point["y"].asLong();
+ _has_point = true;
+ }
+ if (radius.valid()) {
+ _radius = radius.asLong();
+ }
+ if (aspect.valid()) {
+ _x_aspect = aspect.asLong();
+ }
+ if (bbox.valid()) {
+ _min_x = bbox["x"][0].asLong();
+ _max_x = bbox["x"][1].asLong();
+ _min_y = bbox["y"][0].asLong();
+ _max_y = bbox["y"][1].asLong();
+ _has_bounding_box = true;
+ }
+ if (_has_point || _has_bounding_box) {
+ _valid = true;
+ } else {
+ _parseError = "Neither point nor bounding box found";
+ }
+ return _valid;
+}
+
GeoLocation
GeoLocationParser::getGeoLocation() const
{
+ if (! _valid) {
+ return GeoLocation();
+ }
GeoLocation::Aspect aspect(_x_aspect);
if (_has_bounding_box) {
GeoLocation::Range x_range{_min_x, _max_x};
diff --git a/searchlib/src/vespa/searchlib/common/geo_location_parser.h b/searchlib/src/vespa/searchlib/common/geo_location_parser.h
index 8936a620d21..7d725f4a035 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location_parser.h
+++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.h
@@ -17,6 +17,9 @@ class GeoLocationParser
public:
GeoLocationParser();
+ bool parseNoField(const std::string &locStr);
+ bool parseWithField(const std::string &locStr);
+
bool parseOldFormat(const std::string &locStr);
bool parseOldFormatWithField(const std::string &str);
@@ -42,6 +45,7 @@ private:
const char *_parseError;
bool correctDimensionalitySkip(const char * &p);
+ bool parseJsonFormat(const std::string &locStr);
};
} // namespace
diff --git a/searchlib/src/vespa/searchlib/common/locationiterators.cpp b/searchlib/src/vespa/searchlib/common/locationiterators.cpp
index d90ed3b41f3..413930522c6 100644
--- a/searchlib/src/vespa/searchlib/common/locationiterators.cpp
+++ b/searchlib/src/vespa/searchlib/common/locationiterators.cpp
@@ -7,6 +7,108 @@
#include <vespa/log/log.h>
LOG_SETUP(".searchlib.common.locationiterators");
+namespace search::common {
+
+class LocationIterator : public search::queryeval::SearchIterator
+{
+private:
+ static constexpr double pi = 3.14159265358979323846;
+ // microdegrees -> degrees -> radians -> km (using Earth mean radius)
+ static constexpr double udeg_to_km = 1.0e-6 * (pi / 180.0) * 6371.0088;
+ search::fef::TermFieldMatchData & _tfmd;
+ const unsigned int _numDocs;
+ const bool _strict;
+ const Location & _location;
+ uint32_t _num_values;
+ std::vector<search::AttributeVector::largeint_t> _pos;
+
+ void doSeek(uint32_t docId) override;
+ void doUnpack(uint32_t docId) override;
+public:
+ LocationIterator(search::fef::TermFieldMatchData &tfmd,
+ unsigned int numDocs,
+ bool strict,
+ const Location & location);
+ ~LocationIterator() override;
+};
+
+LocationIterator::LocationIterator(search::fef::TermFieldMatchData &tfmd,
+ unsigned int numDocs,
+ bool strict,
+ const Location & location)
+ : SearchIterator(),
+ _tfmd(tfmd),
+ _numDocs(numDocs),
+ _strict(strict),
+ _location(location),
+ _num_values(0),
+ _pos()
+{
+ _pos.resize(1); //Need at least 1 entry as the singlevalue attributes does not honour given size.
+ LOG(debug, "created LocationIterator(numDocs=%u)\n", numDocs);
+};
+
+
+LocationIterator::~LocationIterator() = default;
+
+void
+LocationIterator::doSeek(uint32_t docId)
+{
+ while (__builtin_expect(docId < getEndId(), true)) {
+ if (__builtin_expect(docId >= _numDocs, false)) {
+ break;
+ }
+ _num_values = _location.getVec()->get(docId, &_pos[0], _pos.size());
+ while (_num_values > _pos.size()) {
+ _pos.resize(_num_values);
+ _num_values = _location.getVec()->get(docId, &_pos[0], _pos.size());
+ }
+ for (uint32_t i = 0; i < _num_values; i++) {
+ int64_t docxy(_pos[i]);
+ if (_location.inside_limit(docxy)) {
+ setDocId(docId);
+ return;
+ }
+ }
+ if (!_strict) {
+ return;
+ }
+ ++docId;
+ }
+ setAtEnd();
+}
+
+void
+LocationIterator::doUnpack(uint32_t docId)
+{
+ uint64_t sqabsdist = std::numeric_limits<uint64_t>::max();
+ int32_t docx = 0;
+ int32_t docy = 0;
+ // use _num_values from _pos fetched in doSeek()
+ for (uint32_t i = 0; i < _num_values; i++) {
+ int64_t docxy(_pos[i]);
+ vespalib::geo::ZCurve::decode(docxy, &docx, &docy);
+ uint64_t sqdist = _location.sq_distance_to({docx, docy});
+ if (sqdist < sqabsdist) {
+ sqabsdist = sqdist;
+ }
+ }
+ double dist = std::sqrt(double(sqabsdist));
+ double score = 1.0 / (1.0 + (udeg_to_km * dist));
+ LOG(debug, "unpack LI(%u) score %f\n", docId, score);
+ LOG(debug, "distance: %f micro-degrees ~= %f km", dist, udeg_to_km * dist);
+ _tfmd.setRawScore(docId, score);
+}
+
+std::unique_ptr<search::queryeval::SearchIterator>
+create_location_iterator(search::fef::TermFieldMatchData &tfmd, unsigned int numDocs,
+ bool strict, const Location & location)
+{
+ return std::make_unique<LocationIterator>(tfmd, numDocs, strict, location);
+}
+
+} // namespace
+
using namespace search::common;
class FastS_2DZLocationIterator : public search::queryeval::SearchIterator
diff --git a/searchlib/src/vespa/searchlib/common/locationiterators.h b/searchlib/src/vespa/searchlib/common/locationiterators.h
index e345bcae4fe..d963ac2e479 100644
--- a/searchlib/src/vespa/searchlib/common/locationiterators.h
+++ b/searchlib/src/vespa/searchlib/common/locationiterators.h
@@ -4,9 +4,19 @@
#include <vespa/searchlib/queryeval/searchiterator.h>
#include <vespa/searchlib/common/location.h>
+#include <vespa/searchlib/fef/termfieldmatchdata.h>
+
+namespace search::common {
+
+std::unique_ptr<search::queryeval::SearchIterator>
+create_location_iterator(search::fef::TermFieldMatchData &tfmd,
+ unsigned int numDocs,
+ bool strict,
+ const Location & location);
+
+} // namespace
std::unique_ptr<search::queryeval::SearchIterator>
FastS_AllocLocationIterator(unsigned int numDocs,
bool strict,
const search::common::Location & location);
-
diff --git a/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h b/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h
index 7c6a84916f4..d51b29cbfe3 100644
--- a/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h
+++ b/searchlib/src/vespa/searchlib/fef/iqueryenvironment.h
@@ -6,7 +6,7 @@
#include "objectstore.h"
#include <vespa/searchcommon/attribute/iattributecontext.h>
-namespace search::common { class GeoLocationSpec; }
+namespace search::common { struct GeoLocationSpec; }
namespace search::fef {
diff --git a/searchlib/src/vespa/searchlib/query/tree/location.cpp b/searchlib/src/vespa/searchlib/query/tree/location.cpp
index 6e678f9e682..44f0b82d304 100644
--- a/searchlib/src/vespa/searchlib/query/tree/location.cpp
+++ b/searchlib/src/vespa/searchlib/query/tree/location.cpp
@@ -33,12 +33,13 @@ Location::Location(const Rectangle &rect)
bool
Location::operator==(const Location &other) const
{
- auto me = getOldFormatString();
- auto it = other.getOldFormatString();
+ auto me = getJsonFormatString();
+ auto it = other.getJsonFormatString();
if (me == it) {
return true;
} else {
// dump 'me' and 'it' here if unit tests fail
+ // fprintf(stderr, "me='%s', it='%s'\n", me.c_str(), it.c_str());
return false;
}
}
@@ -69,8 +70,37 @@ Location::getOldFormatString() const
return buf.str();
}
+std::string
+Location::getJsonFormatString() const
+{
+ // Only produce what search::common::GeoLocationParser can parse
+ vespalib::asciistream buf;
+ buf << "{";
+ if (has_point) {
+ buf << "p:{x:" << point.x << ",y:" << point.y << "}";
+ if (has_radius()) {
+ buf << "," << "r:" << radius;
+ }
+ if (x_aspect.active()) {
+ buf << "," << "a:" << x_aspect.multiplier;
+ }
+ }
+ if (bounding_box.active()) {
+ if (has_point) {
+ buf << ",";
+ }
+ buf << "b:{x:[" << bounding_box.x.low
+ << "," << bounding_box.x.high
+ << "],y:[" << bounding_box.y.low
+ << "," << bounding_box.y.high
+ << "]}" ;
+ }
+ buf << "}";
+ return buf.str();
+}
+
vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc) {
return out << loc.getOldFormatString();
}
-}
+} // namespace
diff --git a/searchlib/src/vespa/searchlib/query/tree/location.h b/searchlib/src/vespa/searchlib/query/tree/location.h
index 6b8090f45e1..143282e2958 100644
--- a/searchlib/src/vespa/searchlib/query/tree/location.h
+++ b/searchlib/src/vespa/searchlib/query/tree/location.h
@@ -22,6 +22,7 @@ public:
bool operator==(const Location &other) const;
std::string getOldFormatString() const;
+ std::string getJsonFormatString() const;
};
vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc);
diff --git a/storage/src/vespa/storage/distributor/distributor.h b/storage/src/vespa/storage/distributor/distributor.h
index 84e195fdff2..fcc08030764 100644
--- a/storage/src/vespa/storage/distributor/distributor.h
+++ b/storage/src/vespa/storage/distributor/distributor.h
@@ -25,11 +25,11 @@
#include <unordered_map>
namespace storage {
+ struct DoneInitializeHandler;
+ class HostInfo;
+}
-struct DoneInitializeHandler;
-class HostInfo;
-
-namespace distributor {
+namespace storage::distributor {
class DistributorBucketSpaceRepo;
class SimpleMaintenanceScanner;
@@ -342,5 +342,4 @@ private:
bool _must_send_updated_host_info;
};
-} // distributor
-} // storage
+}
diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
index 70dd215cc1d..5a03e05d563 100644
--- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
+++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp
@@ -41,6 +41,8 @@ VisitorOperation::BucketInfo::toString() const
return ost.str();
}
+VisitorOperation::SuperBucketInfo::~SuperBucketInfo() = default;
+
VisitorOperation::VisitorOperation(
DistributorComponent& owner,
DistributorBucketSpace &bucketSpace,
diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
index fdfe60731f5..42b0bd56b9e 100644
--- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
+++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.h
@@ -74,6 +74,7 @@ private:
subBucketsCompletelyExpanded(false)
{
}
+ ~SuperBucketInfo();
};
diff --git a/storage/src/vespa/storage/persistence/fieldvisitor.h b/storage/src/vespa/storage/persistence/fieldvisitor.h
index 99558fe6e9c..688874742a6 100644
--- a/storage/src/vespa/storage/persistence/fieldvisitor.h
+++ b/storage/src/vespa/storage/persistence/fieldvisitor.h
@@ -15,7 +15,7 @@ namespace storage {
class FieldVisitor : public document::select::Visitor {
private:
- document::DocumentType _docType;
+ const document::DocumentType & _docType;
document::Field::Set::Builder _fields;
public:
diff --git a/storage/src/vespa/storage/persistence/testandsethelper.cpp b/storage/src/vespa/storage/persistence/testandsethelper.cpp
index ed396cd522e..9232abc5c8a 100644
--- a/storage/src/vespa/storage/persistence/testandsethelper.cpp
+++ b/storage/src/vespa/storage/persistence/testandsethelper.cpp
@@ -69,7 +69,7 @@ TestAndSetHelper::retrieveAndMatch(spi::Context & context) {
auto docPtr = result.getDocumentPtr();
if (_docSelectionUp->contains(*docPtr) != document::select::Result::True) {
return api::ReturnCode(api::ReturnCode::TEST_AND_SET_CONDITION_FAILED,
- vespalib::make_string("Condition did not match document partition=%d, nodeIndex=%d bucket=%lx %s",
+ vespalib::make_string("Condition did not match document partition=%d, nodeIndex=%d bucket=%" PRIx64 " %s",
_thread._env._partition, _thread._env._nodeIndex, _cmd.getBucketId().getRawId(),
_cmd.hasBeenRemapped() ? "remapped" : ""));
}
@@ -81,7 +81,7 @@ TestAndSetHelper::retrieveAndMatch(spi::Context & context) {
}
return api::ReturnCode(api::ReturnCode::TEST_AND_SET_CONDITION_FAILED,
- vespalib::make_string("Document does not exist partition=%d, nodeIndex=%d bucket=%lx %s",
+ vespalib::make_string("Document does not exist partition=%d, nodeIndex=%d bucket=%" PRIx64 " %s",
_thread._env._partition, _thread._env._nodeIndex, _cmd.getBucketId().getRawId(),
_cmd.hasBeenRemapped() ? "remapped" : ""));
}
diff --git a/storage/src/vespa/storage/storageserver/storagenodecontext.cpp b/storage/src/vespa/storage/storageserver/storagenodecontext.cpp
index 75e1f12773f..49390d4e579 100644
--- a/storage/src/vespa/storage/storageserver/storagenodecontext.cpp
+++ b/storage/src/vespa/storage/storageserver/storagenodecontext.cpp
@@ -13,4 +13,6 @@ StorageNodeContext::StorageNodeContext(ComponentRegister::UP compReg, framework:
_componentRegister->setThreadPool(_threadPool);
}
+StorageNodeContext::~StorageNodeContext() = default;
+
} // storage
diff --git a/storage/src/vespa/storage/storageserver/storagenodecontext.h b/storage/src/vespa/storage/storageserver/storagenodecontext.h
index eabca618bfb..163c02ef5af 100644
--- a/storage/src/vespa/storage/storageserver/storagenodecontext.h
+++ b/storage/src/vespa/storage/storageserver/storagenodecontext.h
@@ -40,6 +40,8 @@ struct StorageNodeContext {
*/
FastOS_ThreadPool& getThreadPool() { return _threadPool.getThreadPool(); }
+ ~StorageNodeContext();
+
protected:
// Initialization has been split in two as subclass needs to initialize
// component register before sending it on.
diff --git a/storageapi/src/vespa/storageapi/message/visitor.cpp b/storageapi/src/vespa/storageapi/message/visitor.cpp
index faf58361276..d87f65a72cf 100644
--- a/storageapi/src/vespa/storageapi/message/visitor.cpp
+++ b/storageapi/src/vespa/storageapi/message/visitor.cpp
@@ -4,6 +4,7 @@
#include <vespa/document/fieldset/fieldsets.h>
#include <vespa/vespalib/util/array.hpp>
#include <climits>
+#include <ostream>
namespace storage::api {
diff --git a/zkfacade/pom.xml b/zkfacade/pom.xml
index c160d935788..de542b89b67 100644
--- a/zkfacade/pom.xml
+++ b/zkfacade/pom.xml
@@ -48,7 +48,6 @@
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
- <version>4.2.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java
index 51cb387b734..37b1fa1c9fb 100644
--- a/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java
+++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java
@@ -279,7 +279,7 @@ public class Curator implements AutoCloseable {
*/
public void createAtomically(Path... paths) {
try {
- @SuppressWarnings("deprecation") CuratorTransaction transaction = framework().inTransaction();
+ CuratorTransaction transaction = framework().inTransaction();
for (Path path : paths) {
if ( ! exists(path)) {
transaction = transaction.create().forPath(path.getAbsolute(), new byte[0]).and();
diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/mock/MockCurator.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/mock/MockCurator.java
index 1f583ada7a1..3da7678c44e 100644
--- a/zkfacade/src/main/java/com/yahoo/vespa/curator/mock/MockCurator.java
+++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/mock/MockCurator.java
@@ -12,40 +12,31 @@ import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.curator.recipes.CuratorLockException;
import org.apache.curator.CuratorZookeeperClient;
import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.WatcherRemoveCuratorFramework;
import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
import org.apache.curator.framework.api.ACLCreateModeBackgroundPathAndBytesable;
import org.apache.curator.framework.api.ACLCreateModePathAndBytesable;
-import org.apache.curator.framework.api.ACLCreateModeStatBackgroundPathAndBytesable;
import org.apache.curator.framework.api.ACLPathAndBytesable;
-import org.apache.curator.framework.api.ACLableExistBuilderMain;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.BackgroundPathAndBytesable;
import org.apache.curator.framework.api.BackgroundPathable;
import org.apache.curator.framework.api.BackgroundVersionable;
import org.apache.curator.framework.api.ChildrenDeletable;
-import org.apache.curator.framework.api.CreateBackgroundModeStatACLable;
+import org.apache.curator.framework.api.CreateBackgroundModeACLable;
import org.apache.curator.framework.api.CreateBuilder;
-import org.apache.curator.framework.api.CreateBuilder2;
-import org.apache.curator.framework.api.CreateBuilderMain;
-import org.apache.curator.framework.api.CreateProtectACLCreateModePathAndBytesable;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.api.DeleteBuilder;
-import org.apache.curator.framework.api.DeleteBuilderMain;
import org.apache.curator.framework.api.ErrorListenerPathAndBytesable;
import org.apache.curator.framework.api.ErrorListenerPathable;
import org.apache.curator.framework.api.ExistsBuilder;
+import org.apache.curator.framework.api.ExistsBuilderMain;
import org.apache.curator.framework.api.GetACLBuilder;
import org.apache.curator.framework.api.GetChildrenBuilder;
-import org.apache.curator.framework.api.GetConfigBuilder;
import org.apache.curator.framework.api.GetDataBuilder;
import org.apache.curator.framework.api.GetDataWatchBackgroundStatable;
import org.apache.curator.framework.api.PathAndBytesable;
import org.apache.curator.framework.api.Pathable;
-import org.apache.curator.framework.api.ProtectACLCreateModeStatPathAndBytesable;
-import org.apache.curator.framework.api.ReconfigBuilder;
-import org.apache.curator.framework.api.RemoveWatchesBuilder;
+import org.apache.curator.framework.api.ProtectACLCreateModePathAndBytesable;
import org.apache.curator.framework.api.SetACLBuilder;
import org.apache.curator.framework.api.SetDataBackgroundVersionable;
import org.apache.curator.framework.api.SetDataBuilder;
@@ -54,16 +45,13 @@ import org.apache.curator.framework.api.UnhandledErrorListener;
import org.apache.curator.framework.api.VersionPathAndBytesable;
import org.apache.curator.framework.api.WatchPathable;
import org.apache.curator.framework.api.Watchable;
-import org.apache.curator.framework.api.transaction.CuratorMultiTransaction;
import org.apache.curator.framework.api.transaction.CuratorTransaction;
import org.apache.curator.framework.api.transaction.CuratorTransactionBridge;
import org.apache.curator.framework.api.transaction.CuratorTransactionFinal;
import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
import org.apache.curator.framework.api.transaction.TransactionCheckBuilder;
import org.apache.curator.framework.api.transaction.TransactionCreateBuilder;
-import org.apache.curator.framework.api.transaction.TransactionCreateBuilder2;
import org.apache.curator.framework.api.transaction.TransactionDeleteBuilder;
-import org.apache.curator.framework.api.transaction.TransactionOp;
import org.apache.curator.framework.api.transaction.TransactionSetDataBuilder;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.listen.Listenable;
@@ -76,8 +64,6 @@ import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
-import org.apache.curator.framework.schema.SchemaSet;
-import org.apache.curator.framework.state.ConnectionStateErrorPolicy;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.utils.EnsurePath;
import org.apache.zookeeper.CreateMode;
@@ -85,7 +71,6 @@ import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
-import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier;
import java.nio.file.Paths;
import java.time.Duration;
@@ -97,7 +82,6 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -649,101 +633,64 @@ public class MockCurator extends Curator {
// ----- file system methods above. -----
// ----- There's nothing to see unless you are interested in an illustration of -----
// ----- the folly of fluent API's or, more generally, mankind. -----
- private abstract static class MockProtectACLCreateModeStatPathAndBytesable<String>
- implements ProtectACLCreateModeStatPathAndBytesable<String> {
- public BackgroundPathAndBytesable<String> withACL(List<ACL> list) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
+ private abstract class MockBackgroundACLPathAndBytesableBuilder<T> implements PathAndBytesable<T>, ProtectACLCreateModePathAndBytesable<T> {
- public BackgroundPathAndBytesable<String> withACL(List<ACL> list, boolean b) {
+ public BackgroundPathAndBytesable<T> withACL(List<ACL> list) {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- public ProtectACLCreateModeStatPathAndBytesable<String> withMode(CreateMode createMode) {
+ public ACLBackgroundPathAndBytesable<T> withMode(CreateMode createMode) {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
@Override
- public ACLCreateModeBackgroundPathAndBytesable<java.lang.String> withProtection() {
- return null;
- }
-
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground() {
- return null;
- }
-
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground(Object o) {
- return null;
- }
-
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback backgroundCallback) {
- return null;
- }
-
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback backgroundCallback, Object o) {
- return null;
- }
-
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback backgroundCallback, Executor executor) {
- return null;
+ public ACLCreateModeBackgroundPathAndBytesable<String> withProtection() {
+ throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- @Override
- public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback backgroundCallback, Object o, Executor executor) {
- return null;
+ public T forPath(String s, byte[] bytes) throws Exception {
+ throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- @Override
- public ACLBackgroundPathAndBytesable<String> storingStatIn(Stat stat) {
- return null;
+ public T forPath(String s) throws Exception {
+ throw new UnsupportedOperationException("Not implemented in MockCurator");
}
}
- private class MockCreateBuilder implements CreateBuilder {
+ private class MockCreateBuilder extends MockBackgroundACLPathAndBytesableBuilder<String> implements CreateBuilder {
private boolean createParents = false;
private CreateMode createMode = CreateMode.PERSISTENT;
@Override
- public ProtectACLCreateModeStatPathAndBytesable<String> creatingParentsIfNeeded() {
+ public ProtectACLCreateModePathAndBytesable<String> creatingParentsIfNeeded() {
createParents = true;
- return new MockProtectACLCreateModeStatPathAndBytesable<>() {
-
- @Override
- public String forPath(String s, byte[] bytes) throws Exception {
- return createNode(s, bytes, createParents, createMode, fileSystem.root(), listeners);
- }
-
- @Override
- public String forPath(String s) throws Exception {
- return createNode(s, new byte[0], createParents, createMode, fileSystem.root(), listeners);
- }
-
- };
+ return this;
}
@Override
- public ProtectACLCreateModeStatPathAndBytesable<String> creatingParentContainersIfNeeded() {
- return new MockProtectACLCreateModeStatPathAndBytesable<>() {
+ public ACLCreateModeBackgroundPathAndBytesable<String> withProtection() {
+ // Protection against the server crashing after creating the file but before returning to the client.
+ // Not relevant for an in-memory mock, obviously
+ return this;
+ }
- @Override
- public String forPath(String s, byte[] bytes) throws Exception {
- return createNode(s, bytes, createParents, createMode, fileSystem.root(), listeners);
- }
+ public ACLBackgroundPathAndBytesable<String> withMode(CreateMode createMode) {
+ this.createMode = createMode;
+ return this;
+ }
- @Override
- public String forPath(String s) throws Exception {
- return createNode(s, new byte[0], createParents, createMode, fileSystem.root(), listeners);
- }
+ @Override
+ public CreateBackgroundModeACLable compressed() {
+ throw new UnsupportedOperationException("Not implemented in MockCurator");
+ }
- };
+ @Override
+ public ProtectACLCreateModePathAndBytesable<String> creatingParentContainersIfNeeded() {
+ // TODO: Add proper support for container nodes, see https://issues.apache.org/jira/browse/ZOOKEEPER-2163.
+ return creatingParentsIfNeeded();
}
@Override
@@ -752,11 +699,6 @@ public class MockCurator extends Curator {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- @Override
- public ACLCreateModeStatBackgroundPathAndBytesable<String> withProtection() {
- return null;
- }
-
public String forPath(String s) throws Exception {
return createNode(s, new byte[0], createParents, createMode, fileSystem.root(), listeners);
}
@@ -794,50 +736,9 @@ public class MockCurator extends Curator {
public ErrorListenerPathAndBytesable<String> inBackground(BackgroundCallback backgroundCallback, Object o, Executor executor) {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
-
- @Override
- public CreateBuilderMain withTtl(long l) {
- return null;
- }
-
- @Override
- public CreateBuilder2 orSetData() {
- return null;
- }
-
- @Override
- public CreateBuilder2 orSetData(int i) {
- return null;
- }
-
- @Override
- public CreateBackgroundModeStatACLable compressed() {
- return null;
- }
-
- @Override
- public CreateProtectACLCreateModePathAndBytesable<String> storingStatIn(Stat stat) {
- return null;
- }
-
- @Override
- public BackgroundPathAndBytesable<String> withACL(List<ACL> list) {
- return null;
- }
-
- @Override
- public ACLBackgroundPathAndBytesable<String> withMode(CreateMode createMode) {
- this.createMode = createMode;
- return this;
- }
-
- @Override
- public BackgroundPathAndBytesable<String> withACL(List<ACL> list, boolean b) {
- return null;
- }
}
- private static class MockBackgroundPathableBuilder<T> implements BackgroundPathable<T>, Watchable<BackgroundPathable<T>> {
+ private class MockBackgroundPathableBuilder<T> implements BackgroundPathable<T>, Watchable<BackgroundPathable<T>> {
@Override
public ErrorListenerPathable<T> inBackground() {
@@ -920,12 +821,7 @@ public class MockCurator extends Curator {
}
@Override
- public ACLableExistBuilderMain creatingParentsIfNeeded() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public ACLableExistBuilderMain creatingParentContainersIfNeeded() {
+ public ExistsBuilderMain creatingParentContainersIfNeeded() {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
}
@@ -955,10 +851,6 @@ public class MockCurator extends Curator {
return null;
}
- @Override
- public DeleteBuilderMain quietly() {
- return this;
- }
}
private class MockGetDataBuilder extends MockBackgroundPathableBuilder<byte[]> implements GetDataBuilder {
@@ -968,48 +860,18 @@ public class MockCurator extends Curator {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- public byte[] forPath(String path) throws Exception {
- return getData(path, fileSystem.root());
- }
-
@Override
- public ErrorListenerPathable<byte[]> inBackground() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public ErrorListenerPathable<byte[]> inBackground(Object o) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public ErrorListenerPathable<byte[]> inBackground(BackgroundCallback backgroundCallback) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public ErrorListenerPathable<byte[]> inBackground(BackgroundCallback backgroundCallback, Object o) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public ErrorListenerPathable<byte[]> inBackground(BackgroundCallback backgroundCallback, Executor executor) {
+ public WatchPathable<byte[]> storingStatIn(Stat stat) {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
- @Override
- public ErrorListenerPathable<byte[]> inBackground(BackgroundCallback backgroundCallback, Object o, Executor executor) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
+ public byte[] forPath(String path) throws Exception {
+ return getData(path, fileSystem.root());
}
- @Override
- public WatchPathable<byte[]> storingStatIn(Stat stat) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
}
- // extends MockBackgroundACLPathAndBytesableBuilder<Stat>
- private class MockSetDataBuilder implements SetDataBuilder {
+ private class MockSetDataBuilder extends MockBackgroundACLPathAndBytesableBuilder<Stat> implements SetDataBuilder {
@Override
public SetDataBackgroundVersionable compressed() {
@@ -1028,11 +890,6 @@ public class MockCurator extends Curator {
}
@Override
- public Stat forPath(String s) throws Exception {
- return null;
- }
-
- @Override
public ErrorListenerPathAndBytesable<Stat> inBackground() {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
@@ -1134,6 +991,11 @@ public class MockCurator extends Curator {
private CreateMode createMode = CreateMode.PERSISTENT;
@Override
+ public PathAndBytesable<CuratorTransactionBridge> withACL(List<ACL> list) {
+ throw new UnsupportedOperationException("Not implemented in MockCurator");
+ }
+
+ @Override
public ACLCreateModePathAndBytesable<CuratorTransactionBridge> compressed() {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
@@ -1156,20 +1018,6 @@ public class MockCurator extends Curator {
return new MockCuratorTransactionBridge();
}
- @Override
- public TransactionCreateBuilder2 withTtl(long l) {
- return this;
- }
-
- @Override
- public Object withACL(List list, boolean b) {
- return this;
- }
-
- @Override
- public Object withACL(List list) {
- return this;
- }
}
private class MockTransactionDeleteBuilder implements TransactionDeleteBuilder {
@@ -1307,31 +1155,11 @@ public class MockCurator extends Curator {
}
@Override
- public ReconfigBuilder reconfig() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public GetConfigBuilder getConfig() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
public CuratorTransaction inTransaction() {
return new MockCuratorTransactionFinal();
}
@Override
- public CuratorMultiTransaction transaction() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public TransactionOp transactionOp() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
@Deprecated
public void sync(String path, Object backgroundContextObject) {
throw new UnsupportedOperationException("Not implemented in MockCurator");
@@ -1400,241 +1228,10 @@ public class MockCurator extends Curator {
}
@Override
- public WatcherRemoveCuratorFramework newWatcherRemoveCuratorFramework() {
- return new WatcherRemoveCuratorFramework() {
- @Override
- public void removeWatchers() {
-
- }
-
- @Override
- public void start() {
-
- }
-
- @Override
- public void close() {
-
- }
-
- @Override
- public CuratorFrameworkState getState() {
- return null;
- }
-
- @Override
- public boolean isStarted() {
- return false;
- }
-
- @Override
- public CreateBuilder create() {
- return null;
- }
-
- @Override
- public DeleteBuilder delete() {
- return null;
- }
-
- @Override
- public ExistsBuilder checkExists() {
- return null;
- }
-
- @Override
- public GetDataBuilder getData() {
- return null;
- }
-
- @Override
- public SetDataBuilder setData() {
- return null;
- }
-
- @Override
- public GetChildrenBuilder getChildren() {
- return null;
- }
-
- @Override
- public GetACLBuilder getACL() {
- return null;
- }
-
- @Override
- public SetACLBuilder setACL() {
- return null;
- }
-
- @Override
- public ReconfigBuilder reconfig() {
- return null;
- }
-
- @Override
- public GetConfigBuilder getConfig() {
- return null;
- }
-
- @Override
- public CuratorTransaction inTransaction() {
- return null;
- }
-
- @Override
- public CuratorMultiTransaction transaction() {
- return null;
- }
-
- @Override
- public TransactionOp transactionOp() {
- return null;
- }
-
- @Override
- public void sync(String s, Object o) {
-
- }
-
- @Override
- public void createContainers(String s) throws Exception {
-
- }
-
- @Override
- public SyncBuilder sync() {
- return null;
- }
-
- @Override
- public RemoveWatchesBuilder watches() {
- return null;
- }
-
- @Override
- public Listenable<ConnectionStateListener> getConnectionStateListenable() {
- return null;
- }
-
- @Override
- public Listenable<CuratorListener> getCuratorListenable() {
- return null;
- }
-
- @Override
- public Listenable<UnhandledErrorListener> getUnhandledErrorListenable() {
- return null;
- }
-
- @Override
- public CuratorFramework nonNamespaceView() {
- return null;
- }
-
- @Override
- public CuratorFramework usingNamespace(String s) {
- return null;
- }
-
- @Override
- public String getNamespace() {
- return null;
- }
-
- @Override
- public CuratorZookeeperClient getZookeeperClient() {
- return null;
- }
-
- @Override
- public EnsurePath newNamespaceAwareEnsurePath(String s) {
- return null;
- }
-
- @Override
- public void clearWatcherReferences(Watcher watcher) {
-
- }
-
- @Override
- public boolean blockUntilConnected(int i, TimeUnit timeUnit) throws InterruptedException {
- return false;
- }
-
- @Override
- public void blockUntilConnected() throws InterruptedException {
-
- }
-
- @Override
- public WatcherRemoveCuratorFramework newWatcherRemoveCuratorFramework() {
- return null;
- }
-
- @Override
- public ConnectionStateErrorPolicy getConnectionStateErrorPolicy() {
- return null;
- }
-
- @Override
- public QuorumVerifier getCurrentConfig() {
- return null;
- }
-
- @Override
- public SchemaSet getSchemaSet() {
- return null;
- }
-
- @Override
- public boolean isZk34CompatibilityMode() {
- return false;
- }
-
- @Override
- public CompletableFuture<Void> runSafe(Runnable runnable) {
- return null;
- }
- };
-
- }
-
- @Override
- public ConnectionStateErrorPolicy getConnectionStateErrorPolicy() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public QuorumVerifier getCurrentConfig() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public SchemaSet getSchemaSet() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
- public boolean isZk34CompatibilityMode() {
- return false;
- }
-
- @Override
- public CompletableFuture<Void> runSafe(Runnable runnable) {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
- @Override
public SyncBuilder sync() {
throw new UnsupportedOperationException("Not implemented in MockCurator");
}
-
- @Override
- public RemoveWatchesBuilder watches() {
- throw new UnsupportedOperationException("Not implemented in MockCurator");
- }
-
+
}
}
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/api/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/api/package-info.java
index e3da4ab3efa..be9e84013c1 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/api/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/api/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.api;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/api/transaction/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/api/transaction/package-info.java
index 94f8b12894e..be3ece0357b 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/api/transaction/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/api/transaction/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.api.transaction;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/listen/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/listen/package-info.java
index 71ee8ccfff0..79c67cedf75 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/listen/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/listen/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.listen;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/package-info.java
index 2999456bc9d..3e3b8433556 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/recipes/atomic/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/recipes/atomic/package-info.java
index dd1dd7a1899..a607d5dcda5 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/recipes/atomic/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/recipes/atomic/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.recipes.atomic;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/recipes/barriers/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/recipes/barriers/package-info.java
index 4e2aea367de..2db4beef75f 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/recipes/barriers/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/recipes/barriers/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.recipes.barriers;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/recipes/cache/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/recipes/cache/package-info.java
index ad6913d6381..0465bbf2039 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/recipes/cache/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/recipes/cache/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.recipes.cache;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/recipes/locks/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/recipes/locks/package-info.java
index 4307c09e30a..63b067bcffc 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/recipes/locks/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/recipes/locks/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.recipes.locks;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/framework/state/package-info.java b/zkfacade/src/main/java/org/apache/curator/framework/state/package-info.java
index 4a10e20318d..eec4f00ddb4 100644
--- a/zkfacade/src/main/java/org/apache/curator/framework/state/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/framework/state/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.framework.state;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/package-info.java b/zkfacade/src/main/java/org/apache/curator/package-info.java
index 232a5fd46f3..120aa4558d2 100644
--- a/zkfacade/src/main/java/org/apache/curator/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;
diff --git a/zkfacade/src/main/java/org/apache/curator/retry/package-info.java b/zkfacade/src/main/java/org/apache/curator/retry/package-info.java
index f45a0d927a5..98130481c4c 100644
--- a/zkfacade/src/main/java/org/apache/curator/retry/package-info.java
+++ b/zkfacade/src/main/java/org/apache/curator/retry/package-info.java
@@ -1,5 +1,5 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-@ExportPackage(version = @Version(major = 4, minor = 3, micro = 0))
+@ExportPackage(version = @Version(major = 2, minor = 13, micro = 0))
package org.apache.curator.retry;
import com.yahoo.osgi.annotation.ExportPackage;
import com.yahoo.osgi.annotation.Version;