summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build_settings.cmake8
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java2
-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.java27
-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.java131
-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.java47
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java18
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java26
-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.java46
-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/searchdefinition/derived/NearestNeighborTestCase.java5
-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.java24
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessControlTest.java295
-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-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java7
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java35
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java51
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/benchmark/LoadTester.java13
-rw-r--r--config_test/pom.xml2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java60
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java56
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java62
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java52
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java37
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java14
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java13
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java7
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java20
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java4
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/Location.java154
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/BoolItem.java4
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/GeoLocationItem.java9
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/IntItem.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/QueryException.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/RegExpItem.java3
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/SegmentItem.java4
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/querytransform/PhraseMatcher.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/searcher/PosSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/Query.java22
-rw-r--r--container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java32
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/GroupingValidator.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java87
-rw-r--r--container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java44
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/PageTemplateSearcher.java72
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderMappingVisitor.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderReferenceCreatingVisitor.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/config/PageTemplateXMLReader.java62
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java10
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Resolution.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/Model.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ParameterParser.java15
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/SelectParser.java33
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/Sorting.java9
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java9
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java11
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/compiled/Binding.java1
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/profile/types/FieldDescription.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java7
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/rewrite/rewriters/GenericExpansionRewriter.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/textserialize/item/ItemContext.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/textserialize/item/TermConverter.java3
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/textserialize/item/TypeCheck.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/query/textserialize/serializer/Serializer.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/BooleanAttributeParser.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java19
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/WandSearcher.java13
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java5
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java21
-rw-r--r--container-search/src/main/java/com/yahoo/search/statistics/PeakQpsSearcher.java4
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java27
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/OperatorNode.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/ProgramParser.java32
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/YqlParser.java11
-rw-r--r--container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java9
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/query/ItemsCommonStuffTestCase.java10
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/test/QueryTestCase.java6
-rw-r--r--container-search/src/test/java/com/yahoo/search/grouping/UniqueGroupingSearcherTestCase.java6
-rw-r--r--container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java2
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java17
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java17
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/types/test/NativePropertiesTestCase.java9
-rw-r--r--container-search/src/test/java/com/yahoo/search/query/profile/types/test/QueryProfileTypeTestCase.java6
-rw-r--r--container-search/src/test/java/com/yahoo/search/querytransform/test/SortingDegraderTestCase.java13
-rw-r--r--container-search/src/test/java/com/yahoo/search/searchers/test/InputCheckingSearcherTestCase.java4
-rw-r--r--container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java8
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java4
-rw-r--r--container-search/src/test/java/com/yahoo/select/SelectTestCase.java17
-rw-r--r--container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsVisitorTestCase.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/DeploymentStatistics.java21
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java80
-rw-r--r--default_build_settings.cmake13
-rw-r--r--functions.cmake20
-rw-r--r--hosted-tenant-base/pom.xml2
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/test/TestTimer.java23
-rw-r--r--logd/src/logd/CMakeLists.txt5
-rw-r--r--model-integration/src/test/models/onnx/simple/simple.onnx6
-rwxr-xr-xmodel-integration/src/test/models/onnx/simple/simple.py2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java3
-rw-r--r--parent/pom.xml11
-rw-r--r--processing/abi-spec.json13
-rw-r--r--processing/src/main/java/com/yahoo/processing/IllegalInputException.java25
-rw-r--r--processing/src/main/java/com/yahoo/processing/request/CloneHelper.java6
-rw-r--r--processing/src/main/java/com/yahoo/processing/response/DefaultIncomingData.java39
-rw-r--r--searchcore/src/tests/proton/matching/query_test.cpp20
-rw-r--r--searchcore/src/tests/proton/matching/termdataextractor_test.cpp8
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/query.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/termdataextractor.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp1
-rw-r--r--searchlib/src/tests/common/location/geo_location_test.cpp276
-rw-r--r--searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp15
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.cpp98
-rw-r--r--searchlib/src/vespa/searchlib/common/geo_location_parser.h6
-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/engine/CMakeLists.txt6
-rw-r--r--searchlib/src/vespa/searchlib/features/distancefeature.cpp8
-rw-r--r--searchlib/src/vespa/searchlib/fef/iqueryenvironment.h2
-rw-r--r--searchlib/src/vespa/searchlib/fef/termfieldmatchdata.h2
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.cpp38
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/location.h1
-rw-r--r--searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h4
-rw-r--r--searchlib/src/vespa/searchlib/tensor/distance_functions.h4
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/docsumstate.cpp4
-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/filestorage/filestorhandlerimpl.cpp3
-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/mbusprot/CMakeLists.txt7
-rw-r--r--storageapi/src/vespa/storageapi/message/visitor.cpp1
-rw-r--r--streamingvisitors/src/vespa/searchvisitor/queryenvironment.cpp2
-rw-r--r--tenant-base/pom.xml2
-rw-r--r--vespa-hadoop/pom.xml2
-rw-r--r--vespalib/src/vespa/vespalib/testkit/test_master.hpp9
182 files changed, 2245 insertions, 1435 deletions
diff --git a/build_settings.cmake b/build_settings.cmake
index d7dd26f5ee7..1a05ffe5073 100644
--- a/build_settings.cmake
+++ b/build_settings.cmake
@@ -66,8 +66,14 @@ else()
set(VESPA_STDCXX_FS_LIB "stdc++fs")
endif()
+if(VESPA_OS_DISTRO_COMBINED STREQUAL "debian 10")
+ unset(VESPA_XXHASH_DEFINE)
+else()
+ set(VESPA_XXHASH_DEFINE "-DXXH_INLINE_ALL")
+endif()
+
# C and C++ compiler flags
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -fno-omit-frame-pointer ${C_WARN_OPTS} -fPIC ${VESPA_CXX_ABI_FLAGS} -DXXH_INLINE_ALL -DBOOST_DISABLE_ASSERTS ${VESPA_CPU_ARCH_FLAGS} ${EXTRA_C_FLAGS}")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -fno-omit-frame-pointer ${C_WARN_OPTS} -fPIC ${VESPA_CXX_ABI_FLAGS} ${VESPA_XXHASH_DEFINE} -DBOOST_DISABLE_ASSERTS ${VESPA_CPU_ARCH_FLAGS} ${EXTRA_C_FLAGS}")
# AddressSanitizer/ThreadSanitizer work for both GCC and Clang
if (VESPA_USE_SANITIZER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${VESPA_USE_SANITIZER}")
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
index 62b9cefab78..4c6dccebae4 100644
--- a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
+++ b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java
@@ -197,7 +197,7 @@ public class InMemoryProvisioner implements HostProvisioner {
int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex);
while (allocation.size() < nodesInGroup) {
- // Find the smallest host that can fit the requested requested
+ // Find the smallest host that can fit the requested resources
Optional<NodeResources> hostResources = freeNodes.keySet().stream()
.sorted(new MemoryDiskCpu())
.filter(resources -> requestedResources.isUnspecified() || resources.satisfies(requestedResources))
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..1d5736ba7e2
--- /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..3ae531539ef
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/SystemBindingPattern.java
@@ -0,0 +1,27 @@
+// 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);}
+ public static SystemBindingPattern fromHttpPortAndPath(String port, String path) { return new SystemBindingPattern("http", "*", port, path); }
+
+ @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..e96951dc83a 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,21 +3,20 @@ 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 com.yahoo.vespa.model.container.component.chain.Chain;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Helper class for http access control.
@@ -25,11 +24,15 @@ import java.util.stream.Stream;
* @author gjoranv
* @author bjorncs
*/
-public final class AccessControl {
+public class AccessControl {
public static final ComponentId ACCESS_CONTROL_CHAIN_ID = ComponentId.fromString("access-control-chain");
+ public static final ComponentId ACCESS_CONTROL_EXCLUDED_CHAIN_ID = ComponentId.fromString("access-control-excluded-chain");
- public static final List<String> UNPROTECTED_HANDLERS = List.of(
+ private static final int HOSTED_CONTAINER_PORT = 4443;
+
+ // Handlers that are excluded from access control
+ private static final List<String> EXCLUDED_HANDLERS = List.of(
FileStatusHandlerComponent.CLASS,
ContainerCluster.APPLICATION_STATUS_HANDLER_CLASS,
ContainerCluster.BINDINGS_OVERVIEW_HANDLER_CLASS,
@@ -39,18 +42,15 @@ public final class AccessControl {
ApplicationContainerCluster.PROMETHEUS_V1_HANDLER_CLASS
);
- public static final class Builder {
- private String domain;
+ public static class Builder {
+ private final 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) {
@@ -58,102 +58,111 @@ public final class AccessControl {
return this;
}
- public Builder writeEnabled(boolean writeEnalbed) {
- this.writeEnabled = writeEnalbed;
+ public Builder writeEnabled(boolean writeEnabled) {
+ this.writeEnabled = writeEnabled;
return this;
}
- public Builder excludeBinding(String binding) {
+ public Builder excludeBinding(BindingPattern binding) {
this.excludeBindings.add(binding);
return this;
}
public Builder setHandlers(ApplicationContainerCluster cluster) {
this.handlers = cluster.getHandlers();
- this.servlets = cluster.getAllServlets();
return this;
}
public AccessControl build() {
- return new AccessControl(domain, writeEnabled, readEnabled,
- excludeBindings, servlets, handlers, logger);
+ return new AccessControl(domain, writeEnabled, readEnabled, excludeBindings, 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,
- Collection<Servlet> servlets,
- Collection<Handler<?>> handlers,
- DeployLogger logger) {
+ Set<BindingPattern> excludedBindings,
+ 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() {
- return Stream.concat(getHandlerBindings(), getServletBindings())
- .collect(Collectors.toCollection(ArrayList::new));
+ public void configureHttpFilterChains(Http http) {
+ http.setAccessControl(this);
+ addAccessControlFilterChain(http);
+ addAccessControlExcludedChain(http);
+ removeDuplicateBindingsFromAccessControlChain(http);
}
public static boolean hasHandlerThatNeedsProtection(ApplicationContainerCluster cluster) {
- return cluster.getHandlers().stream().anyMatch(AccessControl::handlerNeedsProtection);
- }
-
- private Stream<Binding> getHandlerBindings() {
- return handlers.stream()
- .filter(this::shouldHandlerBeProtected)
- .flatMap(handler -> handler.getServerBindings().stream())
- .map(binding -> accessControlBinding(binding, logger));
+ return cluster.getHandlers().stream()
+ .anyMatch(handler -> ! isExcludedHandler(handler) && hasNonMbusBinding(handler));
}
- private Stream<Binding> getServletBindings() {
- return servlets.stream()
- .filter(this::shouldServletBeProtected)
- .flatMap(AccessControl::servletBindings)
- .map(binding -> accessControlBinding(binding, logger));
+ private void addAccessControlFilterChain(Http http) {
+ http.getFilterChains().add(createChain(ACCESS_CONTROL_CHAIN_ID));
+ http.getBindings().addAll(List.of(createAccessControlBinding("/"), createAccessControlBinding("/*")));
}
- private boolean shouldHandlerBeProtected(Handler<?> handler) {
- return ! isBuiltinGetOnly(handler)
- && handler.getServerBindings().stream().noneMatch(excludedBindings::contains);
+ private void addAccessControlExcludedChain(Http http) {
+ http.getFilterChains().add(createChain(ACCESS_CONTROL_EXCLUDED_CHAIN_ID));
+ for (BindingPattern excludedBinding : excludedBindings) {
+ http.getBindings().add(createAccessControlExcludedBinding(excludedBinding));
+ }
+ for (Handler<?> handler : handlers) {
+ if (isExcludedHandler(handler)) {
+ for (BindingPattern binding : handler.getServerBindings()) {
+ http.getBindings().add(createAccessControlExcludedBinding(binding));
+ }
+ }
+ }
}
- private static boolean isBuiltinGetOnly(Handler<?> handler) {
- return UNPROTECTED_HANDLERS.contains(handler.getClassId().getName());
+ // Remove bindings from access control chain that have binding pattern as a different filter chain
+ private void removeDuplicateBindingsFromAccessControlChain(Http http) {
+ Set<FilterBinding> duplicateBindings = new HashSet<>();
+ for (FilterBinding binding : http.getBindings()) {
+ if (binding.chainId().toId().equals(ACCESS_CONTROL_CHAIN_ID)) {
+ for (FilterBinding otherBinding : http.getBindings()) {
+ if (!binding.chainId().equals(otherBinding.chainId())
+ && binding.binding().equals(otherBinding.binding())) {
+ duplicateBindings.add(binding);
+ }
+ }
+ }
+ }
+ duplicateBindings.forEach(http.getBindings()::remove);
}
- private boolean shouldServletBeProtected(Servlet servlet) {
- return servletBindings(servlet).noneMatch(excludedBindings::contains);
+ private static FilterBinding createAccessControlBinding(String path) {
+ return FilterBinding.create(
+ new ComponentSpecification(ACCESS_CONTROL_CHAIN_ID.stringValue()),
+ SystemBindingPattern.fromHttpPortAndPath(Integer.toString(HOSTED_CONTAINER_PORT), path));
}
- private static Binding accessControlBinding(String binding, DeployLogger logger) {
- return Binding.create(new ComponentSpecification(ACCESS_CONTROL_CHAIN_ID.stringValue()), binding, logger);
+ private static FilterBinding createAccessControlExcludedBinding(BindingPattern excludedBinding) {
+ BindingPattern rewrittenBinding = SystemBindingPattern.fromHttpPortAndPath(
+ Integer.toString(HOSTED_CONTAINER_PORT), excludedBinding.path()); // only keep path from excluded binding
+ return FilterBinding.create(
+ new ComponentSpecification(ACCESS_CONTROL_EXCLUDED_CHAIN_ID.stringValue()),
+ rewrittenBinding);
}
- private static Stream<String> servletBindings(Servlet servlet) {
- return Stream.of("http://*/").map(protocol -> protocol + servlet.bindingPath);
- }
+ private static Chain<Filter> createChain(ComponentId id) { return new Chain<>(FilterChains.emptyChainSpec(id)); }
- private static boolean handlerNeedsProtection(Handler<?> handler) {
- return ! isBuiltinGetOnly(handler) && hasNonMbusBinding(handler);
- }
+ private static boolean isExcludedHandler(Handler<?> handler) { return EXCLUDED_HANDLERS.contains(handler.getClassId().getName()); }
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..1ca54769683
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterBinding.java
@@ -0,0 +1,47 @@
+// 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;
+
+import java.util.Objects;
+
+/**
+ * @author bjorncs
+ */
+public class FilterBinding {
+
+ private final ComponentSpecification chainId;
+ private final BindingPattern binding;
+
+ private FilterBinding(ComponentSpecification chainId, BindingPattern binding) {
+ this.chainId = chainId;
+ this.binding = binding;
+ }
+
+ public static FilterBinding create(ComponentSpecification chainId, BindingPattern binding) {
+ return new FilterBinding(chainId, binding);
+ }
+
+ public ComponentSpecification chainId() {
+ return chainId;
+ }
+
+ public BindingPattern binding() {
+ return binding;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FilterBinding that = (FilterBinding) o;
+ return Objects.equals(chainId, that.chainId) &&
+ Objects.equals(binding, that.binding);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(chainId, 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..f58f5faa382 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()));
+ .id(binding.chainId().stringValue())
+ .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,9 +91,9 @@ public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> impl
ComponentRegistry<ChainedComponent<?>> filters = filterChains.componentsRegistry();
ComponentRegistry<Chain<Filter>> chains = filterChains.allChains();
- for (Binding 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());
+ for (FilterBinding binding: bindings) {
+ if (filters.getComponent(binding.chainId()) == null && chains.getComponent(binding.chainId()) == null)
+ throw new RuntimeException("Can't find filter " + binding.chainId() + " 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..c86d8b206d5 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,9 @@ 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.chain.Chain;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
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;
@@ -25,8 +25,6 @@ import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
-import static com.yahoo.vespa.model.container.http.AccessControl.ACCESS_CONTROL_CHAIN_ID;
-
/**
* @author Tony Vaagenes
* @author gjoranv
@@ -36,19 +34,17 @@ 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) {
accessControl = buildAccessControl(deployState, ancestor, accessControlElem);
- bindings.addAll(accessControl.getBindings());
- filterChains.add(new Chain<>(FilterChains.emptyChainSpec(ACCESS_CONTROL_CHAIN_ID)));
}
} else {
filterChains = new FilterChainsBuilder().newChainsInstance(ancestor);
@@ -56,14 +52,16 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http>
Http http = new Http(filterChains);
http.getBindings().addAll(bindings);
- http.setAccessControl(accessControl);
http.setHttpServer(new JettyHttpServerBuilder().build(deployState, ancestor, spec));
+ if (accessControl != null) {
+ accessControl.configureHttpFilterChains(http);
+ }
return 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 +73,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 +111,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 +121,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..51583588201 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,10 +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.chain.Chain;
+import com.yahoo.vespa.model.container.component.SystemBindingPattern;
+import com.yahoo.vespa.model.container.component.UserBindingPattern;
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;
@@ -93,7 +93,6 @@ import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import static com.yahoo.vespa.model.container.http.AccessControl.ACCESS_CONTROL_CHAIN_ID;
import static java.util.logging.Level.WARNING;
/**
@@ -113,7 +112,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 +277,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();
}
@@ -368,15 +369,12 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
if (http.getAccessControl().isPresent()) return; // access control added explicitly
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())
- .setHandlers(cluster)
- .readEnabled(false)
- .writeEnabled(false)
- .build();
- http.getFilterChains().add(new Chain<>(FilterChains.emptyChainSpec(ACCESS_CONTROL_CHAIN_ID)));
- http.setAccessControl(accessControl);
- http.getBindings().addAll(accessControl.getBindings());
+ new AccessControl.Builder(tenantDomain.value())
+ .setHandlers(cluster)
+ .readEnabled(false)
+ .writeEnabled(false)
+ .build()
+ .configureHttpFilterChains(http);
}
private Http buildHttp(DeployState deployState, ApplicationContainerCluster cluster, Element httpElement) {
@@ -795,8 +793,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 +803,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 +816,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/searchdefinition/derived/NearestNeighborTestCase.java b/config-model/src/test/java/com/yahoo/searchdefinition/derived/NearestNeighborTestCase.java
index 9f57b22fd58..f6374677261 100644
--- a/config-model/src/test/java/com/yahoo/searchdefinition/derived/NearestNeighborTestCase.java
+++ b/config-model/src/test/java/com/yahoo/searchdefinition/derived/NearestNeighborTestCase.java
@@ -2,7 +2,6 @@
package com.yahoo.searchdefinition.derived;
import com.yahoo.component.ComponentId;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry;
import com.yahoo.search.query.profile.config.QueryProfileConfigurer;
@@ -28,9 +27,9 @@ public class NearestNeighborTestCase extends AbstractExportingTestCase {
Query q = new Query("?ranking.features.query(q_vec)=[1,2,3,4,5,6]", // length is 6, not 5
queryProfiles.getComponent("default"));
fail("This should fail when q_vec is parsed as a tensor");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// success
- assertEquals("Invalid request parameter", e.getMessage());
+ assertEquals("Could not set 'ranking.features.query(q_vec)' to '[1,2,3,4,5,6]'", e.getMessage());
} catch (RuntimeException e) {
e.printStackTrace();
throw 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..5b0c13a4038 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,14 +44,14 @@ 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());
- assertEquals("my-request-chain", binding.filterId().getName());
+ FilterBinding binding = first(http.getBindings());
+ assertEquals("my-request-chain", binding.chainId().getName());
assertEquals(MY_CHAIN_BINDING, binding.binding());
Chain<Filter> myChain = http.getFilterChains().allChains().getComponent("my-request-chain");
@@ -62,14 +64,14 @@ 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());
- assertEquals("my-response-chain", binding.filterId().getName());
+ FilterBinding binding = first(http.getBindings());
+ assertEquals("my-response-chain", binding.chainId().getName());
assertEquals(MY_CHAIN_BINDING, binding.binding());
Chain<Filter> myChain = http.getFilterChains().allChains().getComponent("my-response-chain");
@@ -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..4c3a1084005 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,271 +1,182 @@
// 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.http.AccessControl;
+import com.yahoo.vespa.model.container.http.FilterChains;
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;
-import org.w3c.dom.Element;
-import java.util.Collection;
-import java.util.HashSet;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
-import static com.yahoo.config.model.test.TestUtil.joinLines;
import static com.yahoo.vespa.defaults.Defaults.getDefaults;
+import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* @author gjoranv
+ * @author bjorncs
*/
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);
-
@Test
- public void access_control_filter_chain_is_set_up() {
- Element clusterElem = DomBuilderTest.parse(
+ public void access_control_filter_chains_are_set_up() {
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='foo' />",
+ " <access-control domain='my-tenant-domain' />",
" </filtering>",
" </http>");
- Http http = new HttpBuilder().build(root.getDeployState(), root, clusterElem);
- root.freezeModelTopology();
-
- assertTrue(http.getFilterChains().hasChain(AccessControl.ACCESS_CONTROL_CHAIN_ID));
+ FilterChains filterChains = http.getFilterChains();
+ assertTrue(filterChains.hasChain(AccessControl.ACCESS_CONTROL_CHAIN_ID));
+ assertTrue(filterChains.hasChain(AccessControl.ACCESS_CONTROL_EXCLUDED_CHAIN_ID));
}
@Test
public void properties_are_set_from_xml() {
- Element clusterElem = DomBuilderTest.parse(
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='my-domain'/>",
+ " <access-control domain='my-tenant-domain'/>",
" </filtering>",
" </http>");
- Http http = new HttpBuilder().build(root.getDeployState(), root, clusterElem);
- root.freezeModelTopology();
AccessControl accessControl = http.getAccessControl().get();
- assertEquals("Wrong domain.", "my-domain", accessControl.domain);
+ assertEquals("Wrong domain.", "my-tenant-domain", accessControl.domain);
}
@Test
public void read_is_disabled_and_write_is_enabled_by_default() {
- Element clusterElem = DomBuilderTest.parse(
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='foo' />",
+ " <access-control domain='my-tenant-domain'/>",
" </filtering>",
" </http>");
- Http http = new HttpBuilder().build(root.getDeployState(), root, clusterElem);
- root.freezeModelTopology();
-
assertFalse("Wrong default value for read.", http.getAccessControl().get().readEnabled);
assertTrue("Wrong default value for write.", http.getAccessControl().get().writeEnabled);
}
@Test
public void read_and_write_can_be_overridden() {
- Element clusterElem = DomBuilderTest.parse(
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='foo' read='true' write='false'/>",
+ " <access-control domain='my-tenant-domain' read='true' write='false'/>",
" </filtering>",
" </http>");
- Http http = new HttpBuilder().build(root.getDeployState(), root, clusterElem);
- root.freezeModelTopology();
-
assertTrue("Given read value not honoured.", http.getAccessControl().get().readEnabled);
assertFalse("Given write value not honoured.", http.getAccessControl().get().writeEnabled);
}
@Test
- public void access_control_filter_chain_has_correct_handler_bindings() {
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
- " <search/>",
- " <document-api/>",
- " <handler id='custom.Handler'>",
- " <binding>http://*/custom-handler/*</binding>",
- " </handler>",
+ public void access_control_excluded_filter_chain_has_all_bindings_from_excluded_handlers() {
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='foo' />",
+ " <access-control/>",
" </filtering>",
- " </http>",
- "</container>");
-
- Http http = getHttp(clusterElem);
-
- Set<String> foundRequiredBindings = REQUIRED_HANDLER_BINDINGS.stream()
- .filter(requiredBinding -> containsBinding(http.getBindings(), requiredBinding))
- .collect(Collectors.toSet());
- Set<String> missingRequiredBindings = new HashSet<>(REQUIRED_HANDLER_BINDINGS);
- missingRequiredBindings.removeAll(foundRequiredBindings);
- assertTrue("Access control chain was not bound to: " + CollectionUtil.mkString(missingRequiredBindings, ", "),
- missingRequiredBindings.isEmpty());
-
- FORBIDDEN_HANDLER_BINDINGS.forEach(forbiddenPath -> {
- String forbiddenBinding = String.format("http://*%s", forbiddenPath);
- http.getBindings().forEach(
- binding -> assertNotEquals("Access control chain was bound to: " + binding.binding(), binding.binding(), forbiddenBinding));
- });
- }
-
- @Test
- public void handler_can_be_excluded_by_excluding_one_of_its_bindings() {
- final String notExcludedBinding = "http://*/custom-handler/*";
- final String excludedBinding = "http://*/excluded/*";
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
- httpWithExcludedBinding(excludedBinding),
- " <handler id='custom.Handler'>",
- " <binding>" + notExcludedBinding + "</binding>",
- " <binding>" + excludedBinding + "</binding>",
- " </handler>",
- "</container>");
-
- Http http = getHttp(clusterElem);
- assertFalse("Excluded binding was not removed.",
- containsBinding(http.getBindings(), excludedBinding));
- assertFalse("Not all bindings of an excluded handler were removed.",
- containsBinding(http.getBindings(), notExcludedBinding));
+ " </http>");
+ Set<String> actualBindings = getFilterBindings(http, AccessControl.ACCESS_CONTROL_EXCLUDED_CHAIN_ID);
+ assertThat(actualBindings, containsInAnyOrder(
+ "http://*:4443/ApplicationStatus",
+ "http://*:4443/status.html",
+ "http://*:4443/state/v1",
+ "http://*:4443/state/v1/*",
+ "http://*:4443/prometheus/v1",
+ "http://*:4443/prometheus/v1/*",
+ "http://*:4443/metrics/v2",
+ "http://*:4443/metrics/v2/*",
+ "http://*:4443/"));
}
@Test
- 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'>",
- " <path>" + servletPath + "</path>",
- " </servlet>",
- " <rest-api jersey2='true' path='" + restApiPath + "' />",
+ public void access_control_excluded_chain_does_not_contain_any_bindings_from_access_control_chain() {
+ Http http = createModelAndGetHttp(
" <http>",
" <filtering>",
- " <access-control domain='foo' />",
+ " <access-control/>",
" </filtering>",
- " </http>",
- "</container>");
-
- Http http = getHttp(clusterElem);
+ " </http>");
- Set<String> missingRequiredBindings = requiredBindings.stream()
- .filter(requiredBinding -> ! containsBinding(http.getBindings(), requiredBinding))
- .collect(Collectors.toSet());
+ Set<String> bindings = getFilterBindings(http, AccessControl.ACCESS_CONTROL_CHAIN_ID);
+ Set<String> excludedBindings = getFilterBindings(http, AccessControl.ACCESS_CONTROL_EXCLUDED_CHAIN_ID);
- assertTrue("Access control chain was not bound to: " + CollectionUtil.mkString(missingRequiredBindings, ", "),
- missingRequiredBindings.isEmpty());
+ for (String binding : bindings) {
+ assertThat(excludedBindings, not(hasItem(binding)));
+ }
}
- @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;
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
- httpWithExcludedBinding(excludedBinding),
- " <servlet id='foo' class='bar' bundle='baz'>",
- " <path>" + servletPath + "</path>",
- " </servlet>",
- "</container>");
- Http http = getHttp(clusterElem);
- assertFalse("Excluded binding was not removed.",
- containsBinding(http.getBindings(), excludedBinding));
- assertFalse("Not all bindings of an excluded servlet were removed.",
- containsBinding(http.getBindings(), notExcludedBinding));
+ @Test
+ public void access_control_excluded_filter_chain_has_user_provided_excluded_bindings() {
+ Http http = createModelAndGetHttp(
+ " <http>",
+ " <handler id='custom.Handler'>",
+ " <binding>http://*/custom-handler/*</binding>",
+ " </handler>",
+ " <filtering>",
+ " <access-control>",
+ " <exclude>",
+ " <binding>http://*/custom-handler/*</binding>",
+ " <binding>http://*/search/*</binding>",
+ " </exclude>",
+ " </access-control>",
+ " </filtering>",
+ " </http>");
+ Set<String> actualBindings = getFilterBindings(http, AccessControl.ACCESS_CONTROL_EXCLUDED_CHAIN_ID);
+ assertThat(actualBindings, hasItems("http://*:4443/custom-handler/*", "http://*:4443/search/*", "http://*:4443/status.html"));
}
@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;;
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
- httpWithExcludedBinding(excludedBinding),
- " <rest-api jersey2='true' path='" + restApiPath + "' />",
- "</container>");
-
- Http http = getHttp(clusterElem);
- assertFalse("Excluded binding was not removed.",
- containsBinding(http.getBindings(), excludedBinding));
- assertFalse("Not all bindings of an excluded rest-api were removed.",
- containsBinding(http.getBindings(), notExcludedBinding));
-
+ public void access_control_filter_chain_contains_catchall_bindings() {
+ Http http = createModelAndGetHttp(
+ " <http>",
+ " <filtering>",
+ " <access-control/>",
+ " </filtering>",
+ " </http>");
+ Set<String> actualBindings = getFilterBindings(http, AccessControl.ACCESS_CONTROL_CHAIN_ID);
+ assertThat(actualBindings, containsInAnyOrder("http://*:4443/*"));
}
-
@Test
public void access_control_is_implicitly_added_for_hosted_apps() {
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
- nodesXml,
- "</container>" );
- AthenzDomain tenantDomain = AthenzDomain.from("my-tenant-domain");
- DeployState state = new DeployState.Builder().properties(
- new TestProperties()
- .setAthenzDomain(tenantDomain)
- .setHostedVespa(true))
- .build();
- createModel(root, state, null, clusterElem);
- Optional<AccessControl> maybeAccessControl =
- ((ApplicationContainer) root.getProducer("container/container.0")).getHttp().getAccessControl();
+ Http http = createModelAndGetHttp("<container version='1.0'/>");
+ Optional<AccessControl> maybeAccessControl = http.getAccessControl();
assertThat(maybeAccessControl.isPresent(), is(true));
AccessControl accessControl = maybeAccessControl.get();
assertThat(accessControl.writeEnabled, is(false));
assertThat(accessControl.readEnabled, is(false));
- assertThat(accessControl.domain, equalTo(tenantDomain.value()));
+ assertThat(accessControl.domain, equalTo("my-tenant-domain"));
}
@Test
public void access_control_is_implicitly_added_for_hosted_apps_with_existing_http_element() {
- Element clusterElem = DomBuilderTest.parse(
- "<container version='1.0'>",
+ Http http = createModelAndGetHttp(
" <http>",
" <server port='" + getDefaults().vespaWebServicePort() + "' id='main' />",
" <filtering>",
@@ -274,49 +185,33 @@ public class AccessControlTest extends ContainerModelBuilderTestBase {
" <filter id='inner' />",
" </request-chain>",
" </filtering>",
- " </http>",
- nodesXml,
- "</container>" );
- AthenzDomain tenantDomain = AthenzDomain.from("my-tenant-domain");
- DeployState state = new DeployState.Builder().properties(
- new TestProperties()
- .setAthenzDomain(tenantDomain)
- .setHostedVespa(true))
- .build();
- createModel(root, state, null, clusterElem);
- Http http = ((ApplicationContainer) root.getProducer("container/container.0")).getHttp();
+ " </http>");
assertThat(http.getAccessControl().isPresent(), is(true));
assertThat(http.getFilterChains().hasChain(AccessControl.ACCESS_CONTROL_CHAIN_ID), is(true));
assertThat(http.getFilterChains().hasChain(ComponentId.fromString("myChain")), is(true));
}
+ private Http createModelAndGetHttp(String... httpElement) {
+ List<String> servicesXml = new ArrayList<>();
+ servicesXml.add("<container version='1.0'>");
+ servicesXml.addAll(List.of(httpElement));
+ servicesXml.add("</container>");
- private String httpWithExcludedBinding(String excludedBinding) {
- return joinLines(
- " <http>",
- " <filtering>",
- " <access-control domain='foo'>",
- " <exclude>",
- " <binding>" + excludedBinding + "</binding>",
- " </exclude>",
- " </access-control>",
- " </filtering>",
- " </http>");
+ AthenzDomain tenantDomain = AthenzDomain.from("my-tenant-domain");
+ DeployState state = new DeployState.Builder().properties(
+ new TestProperties()
+ .setAthenzDomain(tenantDomain)
+ .setHostedVespa(true))
+ .build();
+ createModel(root, state, null, DomBuilderTest.parse(servicesXml.toArray(String[]::new)));
+ return ((ApplicationContainer) root.getProducer("container/container.0")).getHttp();
}
- private Http getHttp(Element clusterElem) {
- createModel(root, clusterElem);
- ContainerCluster cluster = (ContainerCluster) root.getChildren().get("container");
- Http http = cluster.getHttp();
- assertNotNull(http);
- return http;
+ private static Set<String> getFilterBindings(Http http, ComponentId filerChain) {
+ return http.getBindings().stream()
+ .filter(binding -> binding.chainId().toId().equals(filerChain))
+ .map(binding -> binding.binding().patternString())
+ .collect(Collectors.toSet());
}
- private boolean containsBinding(Collection<Binding> bindings, String binding) {
- for (Binding b : bindings) {
- if (b.binding().contains(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-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java
index fa684ff6046..6bc3809bd54 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java
@@ -45,15 +45,16 @@ public class HostSpec implements Comparable<HostSpec> {
/** Create a host in a hosted system */
public HostSpec(String hostname,
NodeResources realResources,
- NodeResources advertisedResurces,
+ NodeResources advertisedResources,
NodeResources requestedResources,
ClusterMembership membership,
Optional<Version> version,
Optional<NetworkPorts> networkPorts,
Optional<DockerImage> dockerImageRepo) {
- this(hostname, List.of(),
+ this(hostname,
+ List.of(),
realResources,
- advertisedResurces,
+ advertisedResources,
requestedResources,
Optional.of(membership),
version,
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
index 96b189cefe6..e4913643e8d 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializer.java
@@ -6,7 +6,6 @@ import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
@@ -16,7 +15,6 @@ import com.yahoo.slime.SlimeUtils;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
@@ -93,7 +91,7 @@ public class AllocatedHostsSerializer {
object.setString(hostSpecDockerImageRepoKey, repo.repository());
});
});
- host.flavor().ifPresent(flavor -> toSlime(flavor, object)); // TODO: Remove this line after June 2020
+ host.flavor().ifPresent(flavor -> toSlime(flavor, object)); // TODO: Remove this line when 7.272 has been released
toSlime(host.realResources(), object.setObject(realResourcesKey));
toSlime(host.advertisedResources(), object.setObject(advertisedResourcesKey));
host.requestedResources().ifPresent(resources -> toSlime(resources, object.setObject(requestedResourcesKey)));
@@ -124,25 +122,26 @@ public class AllocatedHostsSerializer {
resourcesObject.setString(storageTypeKey, storageTypeToString(resources.storageType()));
}
- public static AllocatedHosts fromJson(byte[] json, Optional<NodeFlavors> nodeFlavors) {
- return fromSlime(SlimeUtils.jsonToSlime(json).get(), nodeFlavors);
+ public static AllocatedHosts fromJson(byte[] json) {
+ return fromSlime(SlimeUtils.jsonToSlime(json).get());
}
- public static AllocatedHosts fromSlime(Inspector inspector, Optional<NodeFlavors> nodeFlavors) {
+ public static AllocatedHosts fromSlime(Inspector inspector) {
Inspector array = inspector.field(mappingKey);
Set<HostSpec> hosts = new LinkedHashSet<>();
array.traverse((ArrayTraverser)(i, host) -> {
- hosts.add(hostFromSlime(host.field(hostSpecKey), nodeFlavors));
+ hosts.add(hostFromSlime(host.field(hostSpecKey)));
});
return AllocatedHosts.withHosts(hosts);
}
- private static HostSpec hostFromSlime(Inspector object, Optional<NodeFlavors> nodeFlavors) {
+ private static HostSpec hostFromSlime(Inspector object) {
+
if (object.field(hostSpecMembershipKey).valid()) { // Hosted
return new HostSpec(object.field(hostSpecHostNameKey).asString(),
- nodeResourcesFromSlime(object.field(realResourcesKey), object, nodeFlavors),
- nodeResourcesFromSlime(object.field(advertisedResourcesKey), object, nodeFlavors),
- optionalNodeResourcesFromSlime(object.field(requestedResourcesKey)), // TODO: Make non-optional after June 2020
+ nodeResourcesFromSlime(object.field(realResourcesKey)),
+ nodeResourcesFromSlime(object.field(advertisedResourcesKey)),
+ optionalNodeResourcesFromSlime(object.field(requestedResourcesKey)), // TODO: Make non-optional when we serialize NodeResources.unspecified()
membershipFromSlime(object),
optionalString(object.field(hostSpecCurrentVespaVersionKey)).map(com.yahoo.component.Version::new),
NetworkPortsSerializer.fromSlime(object.field(hostSpecNetworkPortsKey)),
@@ -162,13 +161,6 @@ public class AllocatedHostsSerializer {
return aliases;
}
- private static Optional<Flavor> flavorFromSlime(Inspector object, Optional<NodeFlavors> nodeFlavors) {
- if (object.field(flavorKey).valid() && nodeFlavors.isPresent() && nodeFlavors.get().exists(object.field(flavorKey).asString()))
- return nodeFlavors.get().getFlavor(object.field(flavorKey).asString());
- else
- return Optional.empty();
- }
-
private static NodeResources nodeResourcesFromSlime(Inspector resources) {
return new NodeResources(resources.field(vcpuKey).asDouble(),
resources.field(memoryKey).asDouble(),
@@ -183,13 +175,6 @@ public class AllocatedHostsSerializer {
return nodeResourcesFromSlime(resources);
}
- private static NodeResources nodeResourcesFromSlime(Inspector resources, Inspector parent,
- Optional<NodeFlavors> nodeFlavors) {
- if ( ! resources.valid()) // TODO: Remove the fallback using nodeFlavors after June 2020
- return flavorFromSlime(parent, nodeFlavors).map(f -> f.resources()).orElse(NodeResources.unspecified);
- return nodeResourcesFromSlime(resources);
- }
-
private static NodeResources.DiskSpeed diskSpeedFromSlime(Inspector diskSpeed) {
switch (diskSpeed.asString()) {
case "fast" : return NodeResources.DiskSpeed.fast;
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
index 30810b79104..700bc389664 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/serialization/AllocatedHostsSerializerTest.java
@@ -5,12 +5,9 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
-import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NetworkPorts;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.NodeResources;
-import com.yahoo.config.provisioning.FlavorsConfig;
import org.junit.Test;
import java.io.IOException;
@@ -28,42 +25,45 @@ import static org.junit.Assert.assertEquals;
*/
public class AllocatedHostsSerializerTest {
+ private static final NodeResources smallSlowDiskSpeedNode = new NodeResources(0.5, 3.1, 4, 1, NodeResources.DiskSpeed.slow);
+ private static final NodeResources bigSlowDiskSpeedNode = new NodeResources(1.0, 6.2, 8, 2, NodeResources.DiskSpeed.slow);
+ private static final NodeResources anyDiskSpeedNode = new NodeResources(0.5, 3.1, 4, 1, NodeResources.DiskSpeed.any);
+
@Test
public void testAllocatedHostsSerialization() throws IOException {
- NodeFlavors configuredFlavors = configuredFlavorsFrom("C/12/45/100", 12, 45, 100, 50, Flavor.Type.BARE_METAL);
Set<HostSpec> hosts = new LinkedHashSet<>();
hosts.add(new HostSpec("empty", List.of(), Optional.empty()));
hosts.add(new HostSpec("with-aliases", List.of("alias1", "alias2"), Optional.empty()));
hosts.add(new HostSpec("allocated",
- NodeResources.unspecified(),
- NodeResources.unspecified(),
- NodeResources.unspecified(),
+ smallSlowDiskSpeedNode,
+ bigSlowDiskSpeedNode,
+ anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
Optional.of(DockerImage.fromString("docker.foo.com:4443/vespa/bar"))),
Optional.empty(),
Optional.empty(),
Optional.of(DockerImage.fromString("docker.foo.com:4443/vespa/bar"))));
hosts.add(new HostSpec("flavor-from-resources-2",
- new NodeResources(0.5, 3.1, 4, 1, NodeResources.DiskSpeed.slow),
- new NodeResources(1.0, 6.2, 8, 2, NodeResources.DiskSpeed.slow),
- new NodeResources(0.5, 3.1, 4, 1, NodeResources.DiskSpeed.any),
+ smallSlowDiskSpeedNode,
+ bigSlowDiskSpeedNode,
+ anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
Optional.empty()),
Optional.empty(),
Optional.empty(),
Optional.empty()));
hosts.add(new HostSpec("with-version",
- NodeResources.unspecified(),
- NodeResources.unspecified(),
- NodeResources.unspecified(),
+ smallSlowDiskSpeedNode,
+ bigSlowDiskSpeedNode,
+ anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
Optional.empty()),
Optional.of(Version.fromString("3.4.5")),
Optional.empty(), Optional.empty()));
hosts.add(new HostSpec("with-ports",
- NodeResources.unspecified(),
- NodeResources.unspecified(),
- NodeResources.unspecified(),
+ smallSlowDiskSpeedNode,
+ bigSlowDiskSpeedNode,
+ anyDiskSpeedNode,
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
Optional.empty()),
Optional.empty(),
@@ -71,11 +71,11 @@ public class AllocatedHostsSerializerTest {
new NetworkPorts.Allocation(4567, "service2", "configId2", "suffix2")))),
Optional.empty()));
- assertAllocatedHosts(AllocatedHosts.withHosts(hosts), configuredFlavors);
+ assertAllocatedHosts(AllocatedHosts.withHosts(hosts));
}
- private void assertAllocatedHosts(AllocatedHosts expectedHosts, NodeFlavors configuredFlavors) throws IOException {
- AllocatedHosts deserializedHosts = fromJson(toJson(expectedHosts), Optional.of(configuredFlavors));
+ private void assertAllocatedHosts(AllocatedHosts expectedHosts) throws IOException {
+ AllocatedHosts deserializedHosts = fromJson(toJson(expectedHosts));
assertEquals(expectedHosts, deserializedHosts);
for (HostSpec expectedHost : expectedHosts.getHosts()) {
@@ -99,17 +99,4 @@ public class AllocatedHostsSerializerTest {
throw new IllegalArgumentException("No host " + hostname + " is present");
}
- private NodeFlavors configuredFlavorsFrom(String flavorName, double cpu, double mem, double disk, double bandwidth, Flavor.Type type) {
- FlavorsConfig.Builder b = new FlavorsConfig.Builder();
- FlavorsConfig.Flavor.Builder flavor = new FlavorsConfig.Flavor.Builder();
- flavor.name(flavorName);
- flavor.minDiskAvailableGb(disk);
- flavor.minCpuCores(cpu);
- flavor.minMainMemoryAvailableGb(mem);
- flavor.bandwidth(bandwidth);
- flavor.environment(type.name());
- b.flavor(flavor);
- return new NodeFlavors(b.build());
- }
-
}
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/config_test/pom.xml b/config_test/pom.xml
index 0abc4e2728a..0d8b1912c61 100644
--- a/config_test/pom.xml
+++ b/config_test/pom.xml
@@ -25,7 +25,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.6.1</version>
+ <version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index b437e961104..eb268546580 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -90,6 +90,7 @@ import java.util.stream.Collectors;
import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER;
import static com.yahoo.config.model.api.container.ContainerServiceType.LOGSERVER_CONTAINER;
+import static com.yahoo.vespa.curator.Curator.CompletionWaiter;
import static com.yahoo.vespa.config.server.filedistribution.FileDistributionUtil.getFileReferencesOnDisk;
import static com.yahoo.vespa.config.server.tenant.TenantRepository.HOSTED_VESPA_TENANT;
import static com.yahoo.yolean.Exceptions.uncheck;
@@ -344,6 +345,54 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
return Deployment.prepared(session, this, hostProvisioner, tenant, timeout, clock, false);
}
+ public Transaction deactivateCurrentActivateNew(Session active, LocalSession prepared, boolean ignoreStaleSessionFailure) {
+ SessionRepository sessionRepository = tenantRepository.getTenant(prepared.getTenantName()).getSessionRepository();
+ Transaction transaction = sessionRepository.createActivateTransaction(prepared);
+ if (active != null) {
+ checkIfActiveHasChanged(prepared, active, ignoreStaleSessionFailure);
+ checkIfActiveIsNewerThanSessionToBeActivated(prepared.getSessionId(), active.getSessionId());
+ transaction.add(active.createDeactivateTransaction().operations());
+ }
+ return transaction;
+ }
+
+ static void checkIfActiveHasChanged(LocalSession session, Session currentActiveSession, boolean ignoreStaleSessionFailure) {
+ long activeSessionAtCreate = session.getActiveSessionAtCreate();
+ log.log(Level.FINE, currentActiveSession.logPre() + "active session id at create time=" + activeSessionAtCreate);
+ if (activeSessionAtCreate == 0) return; // No active session at create
+
+ long sessionId = session.getSessionId();
+ long currentActiveSessionSessionId = currentActiveSession.getSessionId();
+ log.log(Level.FINE, currentActiveSession.logPre() + "sessionId=" + sessionId +
+ ", current active session=" + currentActiveSessionSessionId);
+ if (currentActiveSession.isNewerThan(activeSessionAtCreate) &&
+ currentActiveSessionSessionId != sessionId) {
+ String errMsg = currentActiveSession.logPre() + "Cannot activate session " +
+ sessionId + " because the currently active session (" +
+ currentActiveSessionSessionId + ") has changed since session " + sessionId +
+ " was created (was " + activeSessionAtCreate + " at creation time)";
+ if (ignoreStaleSessionFailure) {
+ log.warning(errMsg + " (Continuing because of force.)");
+ } else {
+ throw new ActivationConflictException(errMsg);
+ }
+ }
+ }
+
+ private static boolean isValidSession(Session session) {
+ return session != null;
+ }
+
+ // As of now, config generation is based on session id, and config generation must be a monotonically
+ // increasing number
+ static void checkIfActiveIsNewerThanSessionToBeActivated(long sessionId, long currentActiveSessionId) {
+ if (sessionId < currentActiveSessionId) {
+ throw new ActivationConflictException("It is not possible to activate session " + sessionId +
+ ", because it is older than current active session (" +
+ currentActiveSessionId + ")");
+ }
+ }
+
// ---------------- Application operations ----------------------------------------------------------------
/**
@@ -605,6 +654,17 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
// ---------------- Session operations ----------------------------------------------------------------
+
+
+ public CompletionWaiter activate(LocalSession session, Session previousActiveSession, ApplicationId applicationId, boolean ignoreSessionStaleFailure) {
+ CompletionWaiter waiter = session.getSessionZooKeeperClient().createActiveWaiter();
+ NestedTransaction transaction = new NestedTransaction();
+ transaction.add(deactivateCurrentActivateNew(previousActiveSession, session, ignoreSessionStaleFailure));
+ hostProvisioner.ifPresent(provisioner -> provisioner.activate(transaction, applicationId, session.getAllocatedHosts().getHosts()));
+ transaction.commit();
+ return waiter;
+ }
+
/**
* Gets the active Session for the given application id.
*
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
index 01a95e8ecdd..8c2e6027691 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
@@ -9,9 +9,6 @@ import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.HostFilter;
import com.yahoo.config.provision.Provisioner;
import java.util.logging.Level;
-import com.yahoo.transaction.NestedTransaction;
-import com.yahoo.transaction.Transaction;
-import com.yahoo.vespa.config.server.ActivationConflictException;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.ApplicationRepository.ActionTimer;
import com.yahoo.vespa.config.server.TimeoutBudget;
@@ -145,11 +142,7 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
CompletionWaiter waiter;
try (Lock lock = tenant.getApplicationRepo().lock(applicationId)) {
previousActiveSession = applicationRepository.getActiveSession(applicationId);
- waiter = session.createActiveWaiter();
- NestedTransaction transaction = new NestedTransaction();
- transaction.add(deactivateCurrentActivateNew(previousActiveSession, session, ignoreSessionStaleFailure));
- hostProvisioner.ifPresent(provisioner -> provisioner.activate(transaction, applicationId, session.getAllocatedHosts().getHosts()));
- transaction.commit();
+ waiter = applicationRepository.activate(session, previousActiveSession, applicationId, ignoreSessionStaleFailure);
}
catch (RuntimeException e) {
throw e;
@@ -189,51 +182,4 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
}
}
- private static Transaction deactivateCurrentActivateNew(Session active, LocalSession prepared, boolean ignoreStaleSessionFailure) {
- Transaction transaction = prepared.createActivateTransaction();
- if (isValidSession(active)) {
- checkIfActiveHasChanged(prepared, active, ignoreStaleSessionFailure);
- checkIfActiveIsNewerThanSessionToBeActivated(prepared.getSessionId(), active.getSessionId());
- transaction.add(active.createDeactivateTransaction().operations());
- }
- return transaction;
- }
-
- private static boolean isValidSession(Session session) {
- return session != null;
- }
-
- private static void checkIfActiveHasChanged(LocalSession session, Session currentActiveSession, boolean ignoreStaleSessionFailure) {
- long activeSessionAtCreate = session.getActiveSessionAtCreate();
- log.log(Level.FINE, currentActiveSession.logPre() + "active session id at create time=" + activeSessionAtCreate);
- if (activeSessionAtCreate == 0) return; // No active session at create
-
- long sessionId = session.getSessionId();
- long currentActiveSessionSessionId = currentActiveSession.getSessionId();
- log.log(Level.FINE, currentActiveSession.logPre() + "sessionId=" + sessionId +
- ", current active session=" + currentActiveSessionSessionId);
- if (currentActiveSession.isNewerThan(activeSessionAtCreate) &&
- currentActiveSessionSessionId != sessionId) {
- String errMsg = currentActiveSession.logPre() + "Cannot activate session " +
- sessionId + " because the currently active session (" +
- currentActiveSessionSessionId + ") has changed since session " + sessionId +
- " was created (was " + activeSessionAtCreate + " at creation time)";
- if (ignoreStaleSessionFailure) {
- log.warning(errMsg + " (Continuing because of force.)");
- } else {
- throw new ActivationConflictException(errMsg);
- }
- }
- }
-
- // As of now, config generation is based on session id, and config generation must be a monotonically
- // increasing number
- private static void checkIfActiveIsNewerThanSessionToBeActivated(long sessionId, long currentActiveSessionId) {
- if (sessionId < currentActiveSessionId) {
- throw new ActivationConflictException("It is not possible to activate session " + sessionId +
- ", because it is older than current active session (" +
- currentActiveSessionId + ")");
- }
- }
-
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java
index 96324ea4320..f842578b657 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java
@@ -1,15 +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.config.server.session;
-import com.yahoo.config.application.api.ApplicationFile;
-import com.yahoo.config.application.api.ApplicationMetaData;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.provision.TenantName;
-import com.yahoo.path.Path;
-import com.yahoo.transaction.Transaction;
-import com.yahoo.vespa.config.server.application.TenantApplications;
-
-import static com.yahoo.vespa.curator.Curator.CompletionWaiter;
/**
* A LocalSession is a session that has been created locally on this configserver. A local session can be edited and
@@ -22,65 +15,14 @@ import static com.yahoo.vespa.curator.Curator.CompletionWaiter;
// TODO: Separate the "application store" and "session" aspects - the latter belongs in the HTTP layer -bratseth
public class LocalSession extends Session {
- protected final ApplicationPackage applicationPackage;
- private final TenantApplications applicationRepo;
-
/**
* Creates a session. This involves loading the application, validating it and distributing it.
*
* @param sessionId The session id for this session.
*/
public LocalSession(TenantName tenant, long sessionId, ApplicationPackage applicationPackage,
- SessionZooKeeperClient sessionZooKeeperClient,
- TenantApplications applicationRepo) {
- super(tenant, sessionId, sessionZooKeeperClient);
- this.applicationPackage = applicationPackage;
- this.applicationRepo = applicationRepo;
- }
-
- public ApplicationFile getApplicationFile(Path relativePath, Mode mode) {
- if (mode.equals(Mode.WRITE)) {
- markSessionEdited();
- }
- return applicationPackage.getFile(relativePath);
- }
-
- void setPrepared() {
- setStatus(Session.Status.PREPARE);
- }
-
- private Transaction createSetStatusTransaction(Status status) {
- return sessionZooKeeperClient.createWriteStatusTransaction(status);
- }
-
- private void setStatus(Session.Status newStatus) {
- sessionZooKeeperClient.writeStatus(newStatus);
- }
-
- public CompletionWaiter createActiveWaiter() {
- return sessionZooKeeperClient.createActiveWaiter();
- }
-
- public Transaction createActivateTransaction() {
- Transaction transaction = createSetStatusTransaction(Status.ACTIVATE);
- transaction.add(applicationRepo.createPutTransaction(sessionZooKeeperClient.readApplicationId(), getSessionId()).operations());
- return transaction;
+ SessionZooKeeperClient sessionZooKeeperClient) {
+ super(tenant, sessionId, sessionZooKeeperClient, applicationPackage);
}
- private void markSessionEdited() {
- setStatus(Session.Status.NEW);
- }
-
- public long getActiveSessionAtCreate() {
- return applicationPackage.getMetaData().getPreviousActiveGeneration();
- }
-
- public enum Mode {
- READ, WRITE
- }
-
- public ApplicationMetaData getMetaData() { return applicationPackage.getMetaData(); }
-
- public ApplicationPackage getApplicationPackage() { return applicationPackage; }
-
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
index 9677c7cf20e..642ac33ab09 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/RemoteSession.java
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.session;
-import com.yahoo.config.application.api.ApplicationMetaData;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.TenantName;
@@ -102,7 +101,7 @@ public class RemoteSession extends Session {
KeeperException.NodeExistsException.class);
Class<? extends Throwable> exceptionClass = e.getCause().getClass();
if (acceptedExceptions.contains(exceptionClass))
- log.log(Level.INFO, "Not able to notify completion for session " + getSessionId() +
+ log.log(Level.FINE, "Not able to notify completion for session " + getSessionId() +
" (" + completionWaiter + ")," +
" node " + (exceptionClass.equals(KeeperException.NoNodeException.class)
? "has been deleted"
@@ -118,8 +117,4 @@ public class RemoteSession extends Session {
transaction.close();
}
- public ApplicationMetaData getMetaData() {
- return sessionZooKeeperClient.loadApplicationPackage().getMetaData();
- }
-
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
index a6818d1e43f..0fc85b5e51a 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java
@@ -3,11 +3,15 @@ package com.yahoo.vespa.config.server.session;
import com.yahoo.component.Version;
import com.yahoo.config.FileReference;
+import com.yahoo.config.application.api.ApplicationFile;
+import com.yahoo.config.application.api.ApplicationMetaData;
+import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.AthenzDomain;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.TenantName;
+import com.yahoo.path.Path;
import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
@@ -27,13 +31,24 @@ public abstract class Session implements Comparable<Session> {
private final long sessionId;
protected final TenantName tenant;
protected final SessionZooKeeperClient sessionZooKeeperClient;
+ protected final Optional<ApplicationPackage> applicationPackage;
protected Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient) {
this.tenant = tenant;
this.sessionId = sessionId;
this.sessionZooKeeperClient = sessionZooKeeperClient;
+ this.applicationPackage = Optional.empty();
}
+ protected Session(TenantName tenant, long sessionId, SessionZooKeeperClient sessionZooKeeperClient,
+ ApplicationPackage applicationPackage) {
+ this.tenant = tenant;
+ this.sessionId = sessionId;
+ this.sessionZooKeeperClient = sessionZooKeeperClient;
+ this.applicationPackage = Optional.of(applicationPackage);
+ }
+
+
public final long getSessionId() {
return sessionId;
}
@@ -42,11 +57,19 @@ public abstract class Session implements Comparable<Session> {
return sessionZooKeeperClient.readStatus();
}
+ public SessionZooKeeperClient getSessionZooKeeperClient() {
+ return sessionZooKeeperClient;
+ }
+
@Override
public String toString() {
return "Session,id=" + sessionId;
}
+ public long getActiveSessionAtCreate() {
+ return getMetaData().getPreviousActiveGeneration();
+ }
+
/**
* The status of this session.
*/
@@ -135,6 +158,31 @@ public abstract class Session implements Comparable<Session> {
// Note: Assumes monotonically increasing session ids
public boolean isNewerThan(long sessionId) { return getSessionId() > sessionId; }
+ public ApplicationMetaData getMetaData() {
+ return applicationPackage.isPresent()
+ ? applicationPackage.get().getMetaData()
+ : sessionZooKeeperClient.loadApplicationPackage().getMetaData();
+ }
+
+ public ApplicationPackage getApplicationPackage() {
+ return applicationPackage.orElseThrow(() -> new RuntimeException("No application package found for " + this));
+ }
+
+ public ApplicationFile getApplicationFile(Path relativePath, LocalSession.Mode mode) {
+ if (mode.equals(Session.Mode.WRITE)) {
+ markSessionEdited();
+ }
+ return getApplicationPackage().getFile(relativePath);
+ }
+
+ private void markSessionEdited() {
+ setStatus(Session.Status.NEW);
+ }
+
+ void setStatus(Session.Status newStatus) {
+ sessionZooKeeperClient.writeStatus(newStatus);
+ }
+
@Override
public int compareTo(Session rhs) {
Long lhsId = getSessionId();
@@ -142,4 +190,8 @@ public abstract class Session implements Comparable<Session> {
return lhsId.compareTo(rhsId);
}
+ public enum Mode {
+ READ, WRITE
+ }
+
}
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 389b661909e..6c4ef469be6 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
@@ -9,7 +9,6 @@ import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.application.provider.DeployData;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.TenantName;
import com.yahoo.io.IOUtils;
import com.yahoo.path.Path;
@@ -47,7 +46,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;
@@ -166,7 +164,7 @@ public class SessionRepository {
getSessionAppDir(sessionId),
session.getApplicationPackage(), sessionZooKeeperClient)
.getConfigChangeActions();
- session.setPrepared();
+ setPrepared(session);
waiter.awaitCompletion(params.getTimeoutBudget().timeLeft());
return actions;
}
@@ -317,8 +315,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 +415,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;
}
});
@@ -489,7 +487,7 @@ public class SessionRepository {
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
sessionZKClient.createNewSession(clock.instant());
Curator.CompletionWaiter waiter = sessionZKClient.getUploadWaiter();
- LocalSession session = new LocalSession(tenantName, sessionId, applicationPackage, sessionZKClient, applicationRepo);
+ LocalSession session = new LocalSession(tenantName, sessionId, applicationPackage, sessionZKClient);
waiter.awaitCompletion(timeoutBudget.timeLeft());
return session;
}
@@ -547,7 +545,7 @@ public class SessionRepository {
ApplicationPackage applicationPackage = createApplicationPackage(applicationFile, applicationId,
sessionId, currentlyActiveSessionId, false);
SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(sessionId);
- return new LocalSession(tenantName, sessionId, applicationPackage, sessionZooKeeperClient, applicationRepo);
+ return new LocalSession(tenantName, sessionId, applicationPackage, sessionZooKeeperClient);
} catch (Exception e) {
throw new RuntimeException("Error creating session " + sessionId, e);
}
@@ -596,7 +594,7 @@ public class SessionRepository {
File sessionDir = getAndValidateExistingSessionAppDir(sessionId);
ApplicationPackage applicationPackage = FilesApplicationPackage.fromFile(sessionDir);
SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId);
- return new LocalSession(tenantName, sessionId, applicationPackage, sessionZKClient, applicationRepo);
+ return new LocalSession(tenantName, sessionId, applicationPackage, sessionZKClient);
}
/**
@@ -654,9 +652,8 @@ public class SessionRepository {
private SessionZooKeeperClient createSessionZooKeeperClient(long sessionId) {
String serverId = componentRegistry.getConfigserverConfig().serverId();
- Optional<NodeFlavors> nodeFlavors = componentRegistry.getZone().nodeFlavors();
Path sessionPath = getSessionPath(sessionId);
- return new SessionZooKeeperClient(curator, componentRegistry.getConfigCurator(), sessionPath, serverId, nodeFlavors);
+ return new SessionZooKeeperClient(curator, componentRegistry.getConfigCurator(), sessionPath, serverId);
}
private File getAndValidateExistingSessionAppDir(long sessionId) {
@@ -697,6 +694,20 @@ public class SessionRepository {
return locksPath.append(String.valueOf(sessionId));
}
+ public Transaction createActivateTransaction(Session session) {
+ Transaction transaction = createSetStatusTransaction(session, Session.Status.ACTIVATE);
+ transaction.add(applicationRepo.createPutTransaction(session.sessionZooKeeperClient.readApplicationId(), session.getSessionId()).operations());
+ return transaction;
+ }
+
+ private Transaction createSetStatusTransaction(Session session, Session.Status status) {
+ return session.sessionZooKeeperClient.createWriteStatusTransaction(status);
+ }
+
+ void setPrepared(Session session) {
+ session.setStatus(Session.Status.PREPARE);
+ }
+
private static class FileTransaction extends AbstractTransaction {
public static FileTransaction from(FileOperation operation) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
index 1b9527f4376..cf1e07788ff 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java
@@ -51,23 +51,21 @@ public class SessionZooKeeperClient {
private final Path sessionPath;
private final Path sessionStatusPath;
private final String serverId; // hostname
- private final Optional<NodeFlavors> nodeFlavors;
- // Only for testing when cache loader does not need cache entries.
+ // Only for testing
+ // TODO: Remove, use the constructor below
public SessionZooKeeperClient(Curator curator, Path sessionPath) {
- this(curator, ConfigCurator.create(curator), sessionPath, "1", Optional.empty());
+ this(curator, ConfigCurator.create(curator), sessionPath, "1");
}
public SessionZooKeeperClient(Curator curator,
ConfigCurator configCurator,
Path sessionPath,
- String serverId,
- Optional<NodeFlavors> nodeFlavors) {
+ String serverId) {
this.curator = curator;
this.configCurator = configCurator;
this.sessionPath = sessionPath;
this.serverId = serverId;
- this.nodeFlavors = nodeFlavors;
this.sessionStatusPath = sessionPath.append(ConfigCurator.SESSIONSTATE_ZK_SUBPATH);
}
@@ -93,7 +91,7 @@ public class SessionZooKeeperClient {
return createCompletionWaiter(PREPARE_BARRIER);
}
- Curator.CompletionWaiter createActiveWaiter() {
+ public Curator.CompletionWaiter createActiveWaiter() {
return createCompletionWaiter(ACTIVE_BARRIER);
}
@@ -134,7 +132,7 @@ public class SessionZooKeeperClient {
}
public ApplicationPackage loadApplicationPackage() {
- return new ZKApplicationPackage(configCurator, sessionPath, nodeFlavors);
+ return new ZKApplicationPackage(configCurator, sessionPath);
}
public ConfigDefinitionRepo getUserConfigDefinitions() {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
index 11cec9efd95..665f37759b4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
@@ -13,7 +13,6 @@ import com.yahoo.config.codegen.DefParser;
import com.yahoo.config.model.application.provider.PreGeneratedFileRegistry;
import com.yahoo.config.provision.AllocatedHosts;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.serialization.AllocatedHostsSerializer;
import com.yahoo.io.IOUtils;
import com.yahoo.io.reader.NamedReader;
@@ -52,17 +51,17 @@ public class ZKApplicationPackage implements ApplicationPackage {
public static final String allocatedHostsNode = "allocatedHosts";
private final ApplicationMetaData metaData;
- public ZKApplicationPackage(ConfigCurator zk, Path sessionPath, Optional<NodeFlavors> nodeFlavors) {
+ public ZKApplicationPackage(ConfigCurator zk, Path sessionPath) {
verifyAppPath(zk, sessionPath);
zkApplication = new ZKApplication(zk, sessionPath);
metaData = readMetaDataFromLiveApp(zkApplication);
importFileRegistries();
- allocatedHosts = importAllocatedHosts(nodeFlavors);
+ allocatedHosts = importAllocatedHosts();
}
- private Optional<AllocatedHosts> importAllocatedHosts(Optional<NodeFlavors> nodeFlavors) {
+ private Optional<AllocatedHosts> importAllocatedHosts() {
if ( ! zkApplication.exists(ZKApplicationPackage.allocatedHostsNode)) return Optional.empty();
- return Optional.of(readAllocatedHosts(nodeFlavors));
+ return Optional.of(readAllocatedHosts());
}
/**
@@ -70,9 +69,9 @@ public class ZKApplicationPackage implements ApplicationPackage {
*
* @return the allocated hosts at this node or empty if there is no data at this path
*/
- private AllocatedHosts readAllocatedHosts(Optional<NodeFlavors> nodeFlavors) {
+ private AllocatedHosts readAllocatedHosts() {
try {
- return AllocatedHostsSerializer.fromJson(zkApplication.getBytes(ZKApplicationPackage.allocatedHostsNode), nodeFlavors);
+ return AllocatedHostsSerializer.fromJson(zkApplication.getBytes(ZKApplicationPackage.allocatedHostsNode));
} catch (Exception e) {
throw new RuntimeException("Unable to read allocated hosts", e);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
index 50a8cac2837..e42fb78f595 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java
@@ -325,6 +325,10 @@ public class ApplicationRepositoryTest {
{
PrepareResult prepareResult = deployApp(testApp);
+
+ assertNotNull(applicationRepository.getActiveSession(applicationId()));
+ assertNotNull(sessionRepository.getLocalSession(prepareResult.sessionId()));
+
try {
applicationRepository.delete(applicationId(), Duration.ZERO);
fail("Should have gotten an exception");
@@ -334,8 +338,7 @@ public class ApplicationRepositoryTest {
// No active session or remote session (deleted in step above), but an exception was thrown above
// A new delete should cleanup and be successful
- RemoteSession activeSession = applicationRepository.getActiveSession(applicationId());
- assertNull(activeSession);
+ assertNull(applicationRepository.getActiveSession(applicationId()));
assertNull(sessionRepository.getLocalSession(prepareResult.sessionId()));
assertTrue(applicationRepository.delete(applicationId()));
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java
index dfc5649433a..deff0aba376 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClientTest.java
@@ -165,7 +165,7 @@ public class ZooKeeperClientTest {
Path hostsPath = app.append(ZKApplicationPackage.allocatedHostsNode);
assertTrue(zk.exists(hostsPath.getAbsolute()));
- AllocatedHosts deserialized = fromJson(zk.getBytes(hostsPath.getAbsolute()), Optional.empty());
+ AllocatedHosts deserialized = fromJson(zk.getBytes(hostsPath.getAbsolute()));
assertEquals(hosts, deserialized.getHosts());
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
index d2f09b802da..c6d241ee534 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java
@@ -12,7 +12,7 @@ import com.yahoo.vespa.config.server.application.CompressedApplicationInputStrea
import com.yahoo.vespa.config.server.application.OrchestratorMock;
import com.yahoo.vespa.config.server.http.HttpErrorResponse;
import com.yahoo.vespa.config.server.http.SessionHandlerTest;
-import com.yahoo.vespa.config.server.session.LocalSession;
+import com.yahoo.vespa.config.server.session.Session;
import com.yahoo.vespa.config.server.tenant.TenantRepository;
import org.junit.Before;
import org.junit.Ignore;
@@ -135,7 +135,7 @@ public class SessionCreateHandlerTest extends SessionHandlerTest {
public void require_that_handler_unpacks_application() throws IOException {
File outFile = CompressedApplicationInputStreamTest.createTarFile();
createHandler().handle(post(outFile));
- ApplicationFile applicationFile = applicationRepository.getApplicationFileFromSession(tenant, 2, "services.xml", LocalSession.Mode.READ);
+ ApplicationFile applicationFile = applicationRepository.getApplicationFileFromSession(tenant, 2, "services.xml", Session.Mode.READ);
assertTrue(applicationFile.exists());
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
index a2ef6aeb578..cf01c9b6713 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/LocalSessionTest.java
@@ -77,31 +77,21 @@ public class LocalSessionTest {
}
@Test
- public void require_that_session_status_is_updated() throws Exception {
- LocalSession session = createSession(TenantName.defaultName(), 3);
- assertThat(session.getStatus(), is(Session.Status.NEW));
- doPrepare(session);
- assertThat(session.getStatus(), is(Session.Status.PREPARE));
- session.createActivateTransaction().commit();
- assertThat(session.getStatus(), is(Session.Status.ACTIVATE));
- }
-
- @Test
public void require_that_marking_session_modified_changes_status_to_new() throws Exception {
LocalSession session = createSession(TenantName.defaultName(), 3);
doPrepare(session);
assertThat(session.getStatus(), is(Session.Status.PREPARE));
- session.getApplicationFile(Path.createRoot(), LocalSession.Mode.READ);
+ session.getApplicationFile(Path.createRoot(), Session.Mode.READ);
assertThat(session.getStatus(), is(Session.Status.PREPARE));
- session.getApplicationFile(Path.createRoot(), LocalSession.Mode.WRITE);
+ session.getApplicationFile(Path.createRoot(), Session.Mode.WRITE);
assertThat(session.getStatus(), is(Session.Status.NEW));
}
@Test
public void require_that_application_file_can_be_fetched() throws Exception {
LocalSession session = createSession(TenantName.defaultName(), 3);
- ApplicationFile f1 = session.getApplicationFile(Path.fromString("services.xml"), LocalSession.Mode.READ);
- ApplicationFile f2 = session.getApplicationFile(Path.fromString("services2.xml"), LocalSession.Mode.READ);
+ ApplicationFile f1 = session.getApplicationFile(Path.fromString("services.xml"), Session.Mode.READ);
+ ApplicationFile f2 = session.getApplicationFile(Path.fromString("services2.xml"), Session.Mode.READ);
assertTrue(f1.exists());
assertFalse(f2.exists());
}
@@ -127,7 +117,7 @@ public class LocalSessionTest {
zkClient.write(Collections.singletonMap(new Version(0, 0, 0), new MockFileRegistry()));
TenantApplications applications = tenantRepository.getTenant(tenantName).getApplicationRepo();
applications.createApplication(applicationId());
- LocalSession session = new LocalSession(tenant, sessionId, FilesApplicationPackage.fromFile(testApp), zkc, applications);
+ LocalSession session = new LocalSession(tenant, sessionId, FilesApplicationPackage.fromFile(testApp), zkc);
session.setApplicationId(applicationId());
return session;
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java
index 4b4605cce7d..32d5d84f323 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java
@@ -48,7 +48,7 @@ public class ZKApplicationPackageTest {
Collections.singleton(new HostSpec("foo.yahoo.com",
TEST_FLAVOR.get().resources(),
TEST_FLAVOR.get().resources(),
- NodeResources.unspecified(),
+ TEST_FLAVOR.get().resources(),
ClusterMembership.from("container/test/0/0", Version.fromString("6.73.1"),
Optional.of(DockerImage.fromString("docker.foo.com:4443/vespa/bar"))),
Optional.of(Version.fromString("6.0.1")), Optional.empty(),
@@ -67,7 +67,7 @@ public class ZKApplicationPackageTest {
@Test
public void testBasicZKFeed() throws IOException {
feed(configCurator, new File(APP));
- ZKApplicationPackage zkApp = new ZKApplicationPackage(configCurator, Path.fromString("/0"), Optional.of(new MockNodeFlavors()));
+ ZKApplicationPackage zkApp = new ZKApplicationPackage(configCurator, Path.fromString("/0"));
assertTrue(Pattern.compile(".*<slobroks>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getServices())).matches());
assertTrue(Pattern.compile(".*<alias>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getHosts())).matches());
assertTrue(Pattern.compile(".*<slobroks>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getFile(Path.fromString("services.xml")).createReader())).matches());
diff --git a/container-search/src/main/java/com/yahoo/prelude/Location.java b/container-search/src/main/java/com/yahoo/prelude/Location.java
index f6228509bbb..3e9c2382f31 100644
--- a/container-search/src/main/java/com/yahoo/prelude/Location.java
+++ b/container-search/src/main/java/com/yahoo/prelude/Location.java
@@ -24,16 +24,9 @@ public class Location {
private int y2 = 1;
// center(x,y), radius
- private int x = 1;
- private int y = 1;
- private int r = 1;
-
- // next three are now UNUSED
- // ranking table, rank multiplier (scale)
- // {0, 1} an int to make parsing and rendering the hit even simpler
- private int tableId = 0;
- private int s = 1;
- private int replace = 0;
+ private int x = 0;
+ private int y = 0;
+ private int r = -1;
private boolean renderCircle = false;
private boolean renderRectangle = false;
@@ -47,14 +40,14 @@ public class Location {
return dimensions == l.dimensions
&& renderCircle == l.renderCircle
&& renderRectangle == l.renderRectangle
- && aspect == l.aspect
- && x1 == l.x1
- && x2 == l.x2
- && y1 == l.y1
- && y2 == l.y2
- && x == l.x
- && y == l.y
- && r == l.r;
+ && this.aspect == l.aspect
+ && this.x1 == l.x1
+ && this.x2 == l.x2
+ && this.y1 == l.y1
+ && this.y2 == l.y2
+ && this.x == l.x
+ && this.y == l.y
+ && this.r == l.r;
}
public boolean hasDimensions() {
@@ -64,10 +57,10 @@ public class Location {
if (hasDimensions() && dimensions != d) {
throw new IllegalArgumentException("already has dimensions="+dimensions+", cannot change it to "+d);
}
- if (d == 1 || d == 2) {
+ if (d == 2) {
dimensions = d;
} else {
- throw new IllegalArgumentException("Illegal location, dimensions must be 1 or 2, but was: "+d);
+ throw new IllegalArgumentException("Illegal location, dimensions must be 2, but was: "+d);
}
}
public int getDimensions() {
@@ -89,13 +82,13 @@ public class Location {
if (px1 > px2) {
throw new IllegalArgumentException("cannot have w > e");
}
- x1 = px1;
- x2 = px2;
+ this.x1 = px1;
+ this.x2 = px2;
if (py1 > py2) {
throw new IllegalArgumentException("cannot have s > n");
}
- y1 = py1;
- y2 = py2;
+ this.y1 = py1;
+ this.y2 = py2;
renderRectangle = true;
}
@@ -104,12 +97,12 @@ public class Location {
//no need to "optimize" for special cases, exactly 0, 30, 45, 60, or 90 degrees won't be input anyway
double degrees = (double) y / 1000000d;
if (degrees <= -90.0 || degrees >= +90.0) {
- aspect = 0;
+ this.aspect = 0;
return;
}
double radians = degrees * Math.PI / 180d;
double cosLatRadians = Math.cos(radians);
- aspect = (long) (cosLatRadians * 4294967295L);
+ this.aspect = (long) (cosLatRadians * 4294967295L);
}
public void setGeoCircle(double ns, double ew, double radius_in_degrees) {
@@ -129,9 +122,9 @@ public class Location {
if (radius_in_degrees < 0) {
pr = -1;
}
- x = px;
- y = py;
- r = pr;
+ this.x = px;
+ this.y = py;
+ this.r = pr;
renderCircle = true;
adjustAspect();
}
@@ -144,9 +137,9 @@ public class Location {
if (radius_in_units < 0) {
radius_in_units = -1;
}
- x = px;
- y = py;
- r = radius_in_units;
+ this.x = px;
+ this.y = py;
+ this.r = radius_in_units;
renderCircle = true;
}
@@ -158,17 +151,12 @@ public class Location {
String rectPart = rectangle.substring(1,endof);
StringTokenizer tokens = new StringTokenizer(rectPart, ",");
setDimensions(Integer.parseInt(tokens.nextToken()));
- if (dimensions == 1) {
- x1 = Integer.parseInt(tokens.nextToken());
- x2 = Integer.parseInt(tokens.nextToken());
- if (tokens.hasMoreTokens()) {
- throw new IllegalArgumentException("Illegal location syntax: "+rectangle);
- }
- } else if (dimensions == 2) {
- x1 = Integer.parseInt(tokens.nextToken());
- y1 = Integer.parseInt(tokens.nextToken());
- x2 = Integer.parseInt(tokens.nextToken());
- y2 = Integer.parseInt(tokens.nextToken());
+ this.x1 = Integer.parseInt(tokens.nextToken());
+ this.y1 = Integer.parseInt(tokens.nextToken());
+ this.x2 = Integer.parseInt(tokens.nextToken());
+ this.y2 = Integer.parseInt(tokens.nextToken());
+ if (tokens.hasMoreTokens()) {
+ throw new IllegalArgumentException("Illegal location syntax: "+rectangle);
}
renderRectangle = true;
String theRest = rectangle.substring(endof+1).trim();
@@ -185,34 +173,24 @@ public class Location {
String circlePart = circle.substring(1,endof);
StringTokenizer tokens = new StringTokenizer(circlePart, ",");
setDimensions(Integer.parseInt(tokens.nextToken()));
- x = Integer.parseInt(tokens.nextToken());
- if (dimensions == 2) {
- y = Integer.parseInt(tokens.nextToken());
- }
- r = Integer.parseInt(tokens.nextToken());
+ this.x = Integer.parseInt(tokens.nextToken());
+ this.y = Integer.parseInt(tokens.nextToken());
+ this.r = Integer.parseInt(tokens.nextToken());
Integer.parseInt(tokens.nextToken()); // was "tableId"
- Integer.parseInt(tokens.nextToken()); // was "scale" (multiplier)
+ Integer.parseInt(tokens.nextToken()); // was "scale"
Integer.parseInt(tokens.nextToken()); // was "replace"
-
- if (dimensions == 1) {
- if (tokens.hasMoreTokens()) {
- throw new IllegalArgumentException("Illegal location syntax: "+circle);
- }
- }
- else {
- if (tokens.hasMoreTokens()) {
- String aspectToken = tokens.nextToken();
- if (aspectToken.equalsIgnoreCase("CalcLatLon")) {
- adjustAspect();
- } else {
- try {
- aspect = Long.parseLong(aspectToken);
- } catch (NumberFormatException nfe) {
- throw new IllegalArgumentException("Aspect "+aspectToken+" for location must be an integer or 'CalcLatLon' for automatic aspect calculation.", nfe);
- }
- if (aspect > 4294967295L || aspect < 0) {
- throw new IllegalArgumentException("Aspect "+aspect+" for location parameter must be less than 4294967296 (2^32)");
- }
+ if (tokens.hasMoreTokens()) {
+ String aspectToken = tokens.nextToken();
+ if (aspectToken.equalsIgnoreCase("CalcLatLon")) {
+ adjustAspect();
+ } else {
+ try {
+ aspect = Long.parseLong(aspectToken);
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Aspect "+aspectToken+" for location must be an integer or 'CalcLatLon' for automatic aspect calculation.", nfe);
+ }
+ if (aspect > 4294967295L || aspect < 0) {
+ throw new IllegalArgumentException("Aspect "+aspect+" for location parameter must be less than 4294967296 (2^32)");
}
}
}
@@ -261,28 +239,20 @@ public class Location {
}
if (renderRectangle) {
ser.append("[").append(dimensions).append(",");
- if (dimensions == 1) {
- ser.append(x1).append(",").
- append(x2);
- }
- else {
- ser.append(x1).append(",").
- append(y1).append(",").
- append(x2).append(",").
- append(y2);
- }
+ ser.append(x1).append(",").
+ append(y1).append(",").
+ append(x2).append(",").
+ append(y2);
ser.append("]");
}
if (renderCircle) {
- ser.append("(").append(dimensions).append(",").append(x);
- if (dimensions == 2) {
- ser.append(",").append(y);
- }
- ser.append(",").append(forBackend ? backendRadius() : r).
- append(",").append(tableId).
- append(",").append(s).
- append(",").append(replace);
- if (dimensions == 2 && aspect != 0) {
+ ser.append("(").append(dimensions).append(",").
+ append(this.x).append(",").append(this.y);
+ ser.append(",").append(forBackend ? backendRadius() : this.r).
+ append(",").append(0). // was "tableId"
+ append(",").append(1). // was "scale"
+ append(",").append(0); // was "replace"
+ if (aspect != 0) {
ser.append(",").append(aspect);
}
ser.append(")");
@@ -296,7 +266,7 @@ public class Location {
*/
public int getBoundingWidth() {
if (renderCircle) {
- return r * 2;
+ return this.r * 2;
} else {
return x2 - x1;
}
@@ -308,7 +278,7 @@ public class Location {
*/
public int getBoundingHeight() {
if (renderCircle) {
- return r * 2;
+ return this.r * 2;
} else {
return y2 - y1;
}
@@ -370,11 +340,11 @@ public class Location {
**/
public double degRadius() {
checkGeoCircle();
- return (r < 0) ? -1.0 : (0.000001 * r);
+ return (this.r < 0) ? -1.0 : (0.000001 * this.r);
}
private int backendRadius() {
- return (r < 0) ? -1 : r;
+ return (this.r < 0) ? -1 : this.r;
}
/**
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/BoolItem.java b/container-search/src/main/java/com/yahoo/prelude/query/BoolItem.java
index 27045629780..542df9d4b8b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/BoolItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/BoolItem.java
@@ -1,6 +1,8 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.prelude.query;
+import com.yahoo.processing.IllegalInputException;
+
import java.nio.ByteBuffer;
/**
@@ -59,7 +61,7 @@ public class BoolItem extends TermItem {
switch (stringValue.toLowerCase()) {
case "true" : return true;
case "false" : return false;
- default: throw new IllegalArgumentException("Expected 'true' or 'false', got '" + stringValue + "'");
+ default: throw new IllegalInputException("Expected 'true' or 'false', got '" + stringValue + "'");
}
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java b/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java
index 64f759dcf9c..4609edb7446 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/CompositeItem.java
@@ -46,7 +46,7 @@ public abstract class CompositeItem extends Item {
Item possibleCycle = i.next();
if (this == possibleCycle) {
- throw new QueryException("Cannot add " + item + " to " + this + " as it would create a cycle");
+ throw new IllegalArgumentException("Cannot add " + item + " to " + this + " as it would create a cycle");
} else if (possibleCycle instanceof CompositeItem) {
ensureNotInSubtree((CompositeItem) possibleCycle);
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/GeoLocationItem.java b/container-search/src/main/java/com/yahoo/prelude/query/GeoLocationItem.java
index 8202c8fb279..ba5270e7af7 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/GeoLocationItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/GeoLocationItem.java
@@ -22,7 +22,7 @@ public class GeoLocationItem extends TermItem {
public GeoLocationItem(Location location) {
this(location, location.getAttribute());
if (! location.hasAttribute()) {
- throw new IllegalArgumentException("missing attribute on location: "+location);
+ throw new IllegalArgumentException("Missing attribute on location: " + location);
}
}
@@ -34,13 +34,14 @@ public class GeoLocationItem extends TermItem {
public GeoLocationItem(Location location, String fieldName) {
super(fieldName, false);
if (location.hasAttribute() && ! location.getAttribute().equals(fieldName)) {
- throw new IllegalArgumentException("inconsistent attribute on location: "+location.getAttribute()+" versus fieldName: "+fieldName);
+ throw new IllegalArgumentException("Inconsistent attribute on location: " + location.getAttribute() +
+ " versus fieldName: " + fieldName);
}
if (! location.isGeoCircle()) {
- throw new IllegalArgumentException("GeoLocationItem only supports Geo Circles, got: "+location);
+ throw new IllegalArgumentException("GeoLocationItem only supports Geo Circles, got: " + location);
}
if (location.hasBoundingBox()) {
- throw new IllegalArgumentException("GeoLocationItem does not support bounding box yet, got: "+location);
+ throw new IllegalArgumentException("GeoLocationItem does not support bounding box, got: " + location);
}
this.location = new Location(location.toString());
this.location.setAttribute(null); // keep this in (superclass) indexName only
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/IntItem.java b/container-search/src/main/java/com/yahoo/prelude/query/IntItem.java
index 714e8f9cb5e..1591d31f749 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/IntItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/IntItem.java
@@ -111,7 +111,7 @@ public class IntItem extends TermItem {
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException("'" + expression + "' is not an int item expression: " +
- "Expected NUMBER, '<'NUMBER, '>'NUMBER or ('['|'<')NUMBER;NUMBER(;NUMBER)?(']'|'>')", e);
+ "Expected NUMBER, '<'NUMBER, '>'NUMBER or ('['|'<')NUMBER;NUMBER(;NUMBER)?(']'|'>')", e);
}
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/QueryException.java b/container-search/src/main/java/com/yahoo/prelude/query/QueryException.java
index 34898827c2e..7d029d69077 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/QueryException.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/QueryException.java
@@ -4,10 +4,11 @@ package com.yahoo.prelude.query;
/**
* Runtime exception to mark errors in query parsing.
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
+ * @deprecated no methods throw this
*/
+@Deprecated // TODO: Remove on Vespa 8
public class QueryException extends RuntimeException {
- private static final long serialVersionUID = -2975856668328596533L;
public QueryException(String message) {
super(message);
@@ -16,4 +17,5 @@ public class QueryException extends RuntimeException {
public QueryException(String message, Throwable cause) {
super(message, cause);
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/RegExpItem.java b/container-search/src/main/java/com/yahoo/prelude/query/RegExpItem.java
index 2a5c6135d71..ec3744306ed 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/RegExpItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/RegExpItem.java
@@ -7,9 +7,10 @@ import java.util.regex.Pattern;
/**
* Match a field with the contained regular expression.
*
- * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ * @author Steinar Knutsen
*/
public class RegExpItem extends TermItem {
+
private String expression;
private Pattern regexp;
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/SegmentItem.java b/container-search/src/main/java/com/yahoo/prelude/query/SegmentItem.java
index 1c3eb261f90..f70bf8021ff 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/SegmentItem.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/SegmentItem.java
@@ -102,7 +102,7 @@ public abstract class SegmentItem extends CompositeItem implements BlockItem {
}
private void dontAdd() {
- throw new QueryException("Tried to add item to an immutable segment.");
+ throw new IllegalArgumentException("Tried to add item to an immutable segment.");
}
public Item removeItem(int index) {
@@ -120,7 +120,7 @@ public abstract class SegmentItem extends CompositeItem implements BlockItem {
}
private void dontRemove() {
- throw new QueryException("Tried to remove an item from an immutable segment.");
+ throw new IllegalArgumentException("Tried to remove an item from an immutable segment.");
}
// TODO: Add a getItemIterator which is safe for immutability
diff --git a/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java b/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java
index e3d1b280a5a..e2dc5df5242 100644
--- a/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java
+++ b/container-search/src/main/java/com/yahoo/prelude/query/parser/AdvancedParser.java
@@ -206,7 +206,7 @@ public class AdvancedParser extends StructuredParser {
if (!tokens.currentIs(LBRACE)) return 0;
tokens.skip(LBRACE);
if (!tokens.currentIsNoIgnore(NUMBER)) throw new IllegalArgumentException("Expected an integer argument");
- int distance=Integer.valueOf(tokens.next().image);
+ int distance = Integer.valueOf(tokens.next().image);
if (!tokens.skip(Token.Kind.RBRACE)) throw new IllegalArgumentException("Expected a right brace following the argument");
return distance;
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/PhraseMatcher.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/PhraseMatcher.java
index f49e49c1771..be33c0ee9e1 100644
--- a/container-search/src/main/java/com/yahoo/prelude/querytransform/PhraseMatcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/querytransform/PhraseMatcher.java
@@ -64,9 +64,9 @@ public class PhraseMatcher {
* @throws IllegalArgumentException if FSA is null
*/
public PhraseMatcher(FSA phraseAutomatonFSA,boolean ignorePluralForm) {
- if(phraseAutomatonFSA==null) throw new IllegalArgumentException("FSA is null");
- this.ignorePluralForm=ignorePluralForm;
- phraseFSA=phraseAutomatonFSA;
+ if (phraseAutomatonFSA == null) throw new NullPointerException("FSA is null");
+ this.ignorePluralForm = ignorePluralForm;
+ phraseFSA = phraseAutomatonFSA;
}
public boolean isEmpty() { return phraseFSA == null; }
diff --git a/container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java
index 318912eab04..eb31b75cd6f 100644
--- a/container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/querytransform/StemmingSearcher.java
@@ -359,7 +359,7 @@ public class StemmingSearcher extends Searcher {
default:
throw new IllegalArgumentException("Unknown segmenting rule: " + current.getSegmentingRule() +
". This is a bug in Vespa, as the implementation has gotten out of sync." +
- " Please create a ticket as soon as possible.");
+ " Please create an issue.");
}
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/PosSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/PosSearcher.java
index 37561d3a0f5..7063a14a389 100644
--- a/container-search/src/main/java/com/yahoo/prelude/searcher/PosSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/searcher/PosSearcher.java
@@ -75,7 +75,7 @@ public class PosSearcher extends Searcher {
loc.setAttribute(posAttribute);
try {
- if (ll == null && xy == null && bb != null) {
+ if (ll == null && xy == null) {
parseBoundingBox(bb, loc);
} else {
if (ll != null && xy != null) {
diff --git a/container-search/src/main/java/com/yahoo/search/Query.java b/container-search/src/main/java/com/yahoo/search/Query.java
index 9e3f6d20e36..4995927f7a2 100644
--- a/container-search/src/main/java/com/yahoo/search/Query.java
+++ b/container-search/src/main/java/com/yahoo/search/Query.java
@@ -10,7 +10,6 @@ import com.yahoo.fs4.MapEncoder;
import java.util.logging.Level;
import com.yahoo.prelude.fastsearch.DocumentDatabase;
import com.yahoo.prelude.query.Highlight;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.prelude.query.textualrepresentation.TextualQueryRepresentation;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.dispatch.Dispatcher;
@@ -413,11 +412,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
if (field.getType() == FieldType.genericQueryProfileType) { // Generic map
CompoundName fullName = prefix.append(field.getName());
for (Map.Entry<String, Object> entry : originalProperties.listProperties(fullName, context).entrySet()) {
- try {
- properties().set(fullName.append(entry.getKey()), entry.getValue(), context);
- } catch (IllegalArgumentException e) {
- throw new QueryException("Invalid request parameter", e);
- }
+ properties().set(fullName.append(entry.getKey()), entry.getValue(), context);
}
}
else if (field.getType() instanceof QueryProfileFieldType) { // Nested arguments
@@ -427,11 +422,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
CompoundName fullName = prefix.append(field.getName());
Object value = originalProperties.get(fullName, context);
if (value != null) {
- try {
- properties().set(fullName, value, context);
- } catch (IllegalArgumentException e) {
- throw new QueryException("Invalid request parameter", e);
- }
+ properties().set(fullName, value, context);
}
}
}
@@ -440,13 +431,8 @@ public class Query extends com.yahoo.processing.Request implements Cloneable {
/** Calls properties.set on all entries in requestMap */
private void setPropertiesFromRequestMap(Map<String, String> requestMap, Properties properties, boolean ignoreSelect) {
for (var entry : requestMap.entrySet()) {
- try {
- if (ignoreSelect && entry.getKey().equals(Select.SELECT)) continue;
- properties.set(entry.getKey(), entry.getValue(), requestMap);
- }
- catch (IllegalArgumentException e) {
- throw new QueryException("Invalid request parameter", e);
- }
+ if (ignoreSelect && entry.getKey().equals(Select.SELECT)) continue;
+ properties.set(entry.getKey(), entry.getValue(), requestMap);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java b/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
index 60c5d42c531..0c38b38179d 100644
--- a/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/federation/FederationSearcher.java
@@ -14,6 +14,7 @@ import com.yahoo.concurrent.CopyOnWriteHashMap;
import com.yahoo.errorhandling.Results;
import com.yahoo.errorhandling.Results.Builder;
import com.yahoo.prelude.IndexFacts;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
@@ -545,8 +546,8 @@ public class FederationSearcher extends ForkingSearcher {
private ComponentSpecification asSourceSpec(String source) {
try {
return new ComponentSpecification(source);
- } catch(Exception e) {
- throw new IllegalArgumentException("The source ref '" + source + "' used for federation is not valid.", e);
+ } catch (Exception e) {
+ throw new IllegalInputException("The source ref '" + source + "' used for federation is not valid.", e);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java b/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java
index 9924a05bb46..b9e0825ab03 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/GroupingQueryParser.java
@@ -12,8 +12,14 @@ import com.yahoo.search.grouping.request.GroupingOperation;
import com.yahoo.search.query.Select;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.PhaseNames;
+import com.yahoo.processing.IllegalInputException;
-import java.util.*;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
/**
* This searcher is responsible for turning the "select" parameter into a corresponding {@link GroupingRequest}. It will
@@ -35,19 +41,23 @@ public class GroupingQueryParser extends Searcher {
@Override
public Result search(Query query, Execution execution) {
- String reqParam = query.properties().getString(PARAM_REQUEST);
- if (reqParam == null) {
+ try {
+ String reqParam = query.properties().getString(PARAM_REQUEST);
+ if (reqParam == null) return execution.search(query);
+
+ List<Continuation> continuations = getContinuations(query.properties().getString(PARAM_CONTINUE));
+ TimeZone zone = getTimeZone(query.properties().getString(PARAM_TIMEZONE, "utc"));
+ for (GroupingOperation op : GroupingOperation.fromStringAsList(reqParam)) {
+ GroupingRequest grpRequest = GroupingRequest.newInstance(query);
+ grpRequest.setRootOperation(op);
+ grpRequest.setTimeZone(zone);
+ grpRequest.continuations().addAll(continuations);
+ }
return execution.search(query);
}
- List<Continuation> continuations = getContinuations(query.properties().getString(PARAM_CONTINUE));
- TimeZone zone = getTimeZone(query.properties().getString(PARAM_TIMEZONE, "utc"));
- for (GroupingOperation op : GroupingOperation.fromStringAsList(reqParam)) {
- GroupingRequest grpRequest = GroupingRequest.newInstance(query);
- grpRequest.setRootOperation(op);
- grpRequest.setTimeZone(zone);
- grpRequest.continuations().addAll(continuations);
+ catch (IllegalArgumentException e) {
+ throw new IllegalInputException(e);
}
- return execution.search(query);
}
private List<Continuation> getContinuations(String param) {
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/GroupingValidator.java b/container-search/src/main/java/com/yahoo/search/grouping/GroupingValidator.java
index 06b030dbc78..cd8578cd728 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/GroupingValidator.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/GroupingValidator.java
@@ -5,6 +5,7 @@ import com.google.inject.Inject;
import com.yahoo.component.chain.dependencies.After;
import com.yahoo.component.chain.dependencies.Before;
import com.yahoo.component.chain.dependencies.Provides;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.grouping.request.AttributeMapLookupValue;
import com.yahoo.vespa.config.search.AttributesConfig;
import com.yahoo.container.QrSearchersConfig;
@@ -80,14 +81,14 @@ public class GroupingValidator extends Searcher {
AttributesConfig.Attribute keyAttribute = attributes.get(keyAttributeName);
AttributesConfig.Attribute keySourceAttribute = attributes.get(keySourceAttributeName);
if (!keySourceAttribute.datatype().equals(keyAttribute.datatype())) {
- throw new IllegalArgumentException("Grouping request references key source attribute '" +
- keySourceAttributeName + "' with data type '" + keySourceAttribute.datatype() +
- "' that is different than data type '" + keyAttribute.datatype() + "' of key attribute '" +
- keyAttributeName + "'");
+ throw new IllegalInputException("Grouping request references key source attribute '" +
+ keySourceAttributeName + "' with data type '" + keySourceAttribute.datatype() +
+ "' that is different than data type '" + keyAttribute.datatype() + "' of key attribute '" +
+ keyAttributeName + "'");
}
if (!keySourceAttribute.collectiontype().equals(AttributesConfig.Attribute.Collectiontype.Enum.SINGLE)) {
- throw new IllegalArgumentException("Grouping request references key source attribute '" +
- keySourceAttributeName + "' which is not of single value type");
+ throw new IllegalInputException("Grouping request references key source attribute '" +
+ keySourceAttributeName + "' which is not of single value type");
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java b/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java
index 420861d2f6c..60805aacd5f 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/request/AddFunction.java
@@ -38,9 +38,9 @@ public class AddFunction extends FunctionNode {
/**
* Constructs a new instance of this class from a list of arguments.
*
- * @param args The arguments to pass to the constructor.
- * @return The created instance.
- * @throws IllegalArgumentException Thrown if the number of arguments is less than 2.
+ * @param args the arguments to pass to the constructor.
+ * @return the created instance.
+ * @throws IllegalArgumentException thrown if the number of arguments is less than 2.
*/
public static AddFunction newInstance(List<GroupingExpression> args) {
if (args.size() < 2) {
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java
index c36c8af5c34..6c6b20973ab 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/request/BucketResolver.java
@@ -24,9 +24,9 @@ public class BucketResolver {
* Pushes the given expression onto this bucket resolver. Once all buckets have been pushed using this method, call
* {@link #resolve(GroupingExpression)} to retrieve to combined grouping expression.
*
- * @param val The expression to push.
- * @param inclusive Whether or not the value is inclusive or not.
- * @throws IllegalArgumentException Thrown if the expression is incompatible.
+ * @param val the expression to push
+ * @param inclusive whether or not the value is inclusive or not
+ * @throws IllegalArgumentException thrown if the expression is incompatible
*/
public BucketResolver push(ConstantValue<?> val, boolean inclusive) {
if (prev == null) {
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java
index c825f3c61de..8b73fa01128 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/request/GroupingOperation.java
@@ -228,8 +228,8 @@ public abstract class GroupingOperation extends GroupingNode {
* method verifies the input level against the operation type, and recursively resolves the level of all argument
* expressions.
*
- * @param level The level of the input data.
- * @throws IllegalArgumentException Thrown if a contained expression is invalid for the given level.
+ * @param level the level of the input data
+ * @throws IllegalArgumentException thrown if a contained expression is invalid for the given level
*/
public void resolveLevel(int level) {
if (groupBy != null) {
@@ -322,12 +322,7 @@ public abstract class GroupingOperation extends GroupingNode {
return this;
}
- /**
- * Return the accuracy of this.
- *
- * @return The accuracy value.
- * @see #setAccuracy(double)
- */
+ /** Return the accuracy of this. */
public double getAccuracy() {
return accuracy;
}
@@ -335,8 +330,8 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Adds an expression to the order-by clause of this operation.
*
- * @param exp The expressions to add to this.
- * @return This, to allow chaining.
+ * @param exp the expressions to add to this
+ * @return this, to allow chaining
*/
public GroupingOperation addOrderBy(GroupingExpression exp) {
orderBy.add(exp);
@@ -346,11 +341,11 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Convenience method to call {@link #addOrderBy(GroupingExpression)} for each element in the given list.
*
- * @param lst The list of expressions to add.
- * @return This, to allow chaining.
+ * @param list the list of expressions to add
+ * @return this, to allow chaining
*/
- public GroupingOperation addOrderBy(List<GroupingExpression> lst) {
- for (GroupingExpression exp : lst) {
+ public GroupingOperation addOrderBy(List<GroupingExpression> list) {
+ for (GroupingExpression exp : list) {
addOrderBy(exp);
}
return this;
@@ -359,7 +354,7 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns the number of expressions in the order-by clause of this.
*
- * @return The expression count.
+ * @return the expression count
*/
public int getNumOrderBy() {
return orderBy.size();
@@ -368,9 +363,9 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns the group-by expression at the given index.
*
- * @param i The index of the expression to return.
- * @return The expression at the given index.
- * @throws IndexOutOfBoundsException If the index is out of range.
+ * @param i the index of the expression to return
+ * @return the expression at the given index
+ * @throws IndexOutOfBoundsException if the index is out of range
*/
public GroupingExpression getOrderBy(int i) {
return orderBy.get(i);
@@ -379,7 +374,7 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns an immutable view to the order-by clause of this.
*
- * @return The expression list.
+ * @return the expression list
*/
public List<GroupingExpression> getOrderBy() {
return Collections.unmodifiableList(orderBy);
@@ -388,8 +383,8 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Adds an expression to the output clause of this operation.
*
- * @param exp The expressions to add to this.
- * @return This, to allow chaining.
+ * @param exp the expressions to add to this
+ * @return this, to allow chaining
*/
public GroupingOperation addOutput(GroupingExpression exp) {
outputs.add(exp);
@@ -399,8 +394,8 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Convenience method to call {@link #addOutput(GroupingExpression)} for each element in the given list.
*
- * @param lst The list of expressions to add.
- * @return This, to allow chaining.
+ * @param lst the list of expressions to add
+ * @return this, to allow chaining
*/
public GroupingOperation addOutputs(List<GroupingExpression> lst) {
for (GroupingExpression exp : lst) {
@@ -412,7 +407,7 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns the number of expressions in the output clause of this.
*
- * @return The expression count.
+ * @return the expression count
*/
public int getNumOutputs() {
return outputs.size();
@@ -421,9 +416,9 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns the output expression at the given index.
*
- * @param i The index of the expression to return.
- * @return The expression at the given index.
- * @throws IndexOutOfBoundsException If the index is out of range.
+ * @param i the index of the expression to return
+ * @return the expression at the given index
+ * @throws IndexOutOfBoundsException If the index is out of range
*/
public GroupingExpression getOutput(int i) {
return outputs.get(i);
@@ -432,7 +427,7 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Returns an immutable view to the output clause of this.
*
- * @return The expression list.
+ * @return the expression list
*/
public List<GroupingExpression> getOutputs() {
return Collections.unmodifiableList(outputs);
@@ -443,8 +438,8 @@ public abstract class GroupingOperation extends GroupingNode {
* during expression evaluation to give the dispatch-node more data to consider when selecting the N groups that are
* to be evaluated further.
*
- * @param precision The precision to set.
- * @return This, to allow chaining.
+ * @param precision the precision to set
+ * @return this, to allow chaining
* @see #setMax(int)
*/
public GroupingOperation setPrecision(int precision) {
@@ -452,11 +447,7 @@ public abstract class GroupingOperation extends GroupingNode {
return this;
}
- /**
- * Returns the precision clause of this.
- *
- * @return The precision.
- */
+ /** Returns the precision clause of this. */
public int getPrecision() {
return precision;
}
@@ -464,11 +455,11 @@ public abstract class GroupingOperation extends GroupingNode {
/**
* Assigns a string as the where clause of this operation.
*
- * @param str The string to assign to this.
- * @return This, to allow chaining.
+ * @param string the string to assign to this
+ * @return this, to allow chaining
*/
- public GroupingOperation setWhere(String str) {
- where = str;
+ public GroupingOperation setWhere(String string) {
+ where = string;
return this;
}
@@ -590,9 +581,9 @@ public abstract class GroupingOperation extends GroupingNode {
* Convenience method to call {@link #fromStringAsList(String)} and assert that the list contains exactly one
* grouping operation.
*
- * @param str The string to parse.
- * @return A grouping operation that corresponds to the string.
- * @throws IllegalArgumentException Thrown if the string could not be parsed as a single operation.
+ * @param str the string to parse
+ * @return a grouping operation that corresponds to the string
+ * @throws IllegalArgumentException thrown if the string could not be parsed as a single operation
*/
public static GroupingOperation fromString(String str) {
List<GroupingOperation> lst = fromStringAsList(str);
@@ -606,15 +597,15 @@ public abstract class GroupingOperation extends GroupingNode {
* Parses the given string as a list of grouping operations. This method never returns null, it either returns a
* list of valid grouping requests or it throws an exception.
*
- * @param str The string to parse.
- * @return A list of grouping operations that corresponds to the string.
- * @throws IllegalArgumentException Thrown if the string could not be parsed.
+ * @param string the string to parse
+ * @return a list of grouping operations that corresponds to the string
+ * @throws IllegalArgumentException thrown if the string could not be parsed
*/
- public static List<GroupingOperation> fromStringAsList(String str) {
- if (str == null || str.trim().length() == 0) {
+ public static List<GroupingOperation> fromStringAsList(String string) {
+ if (string == null || string.trim().length() == 0) {
return Collections.emptyList();
}
- GroupingParserInput input = new GroupingParserInput(str);
+ GroupingParserInput input = new GroupingParserInput(string);
try {
return new GroupingParser(input).requestList();
} catch (ParseException | TokenMgrException e) {
diff --git a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java
index c658d404adb..b0c8fbba059 100644
--- a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java
+++ b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java
@@ -21,8 +21,8 @@ import com.yahoo.language.Linguistics;
import java.util.logging.Level;
import com.yahoo.net.HostName;
import com.yahoo.net.UriTools;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.prelude.query.parser.ParseException;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.rendering.Renderer;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.query.context.QueryContext;
@@ -61,7 +61,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -229,10 +228,8 @@ public class SearchHandler extends LoggingRequestHandler {
try {
try {
return handleBody(request);
- } catch (QueryException e) {
- return (e.getCause() instanceof IllegalArgumentException)
- ? invalidParameterResponse(request, e)
- : illegalQueryResponse(request, e);
+ } catch (IllegalInputException e) {
+ return illegalQueryResponse(request, e);
} catch (RuntimeException e) { // Make sure we generate a valid response even on unexpected errors
log.log(Level.WARNING, "Failed handling " + request, e);
return internalServerErrorResponse(request, e);
@@ -263,10 +260,6 @@ public class SearchHandler extends LoggingRequestHandler {
return new HttpSearchResponse(getHttpResponseStatus(request, result), result, query, renderer);
}
- private HttpResponse invalidParameterResponse(HttpRequest request, RuntimeException e) {
- return errorResponse(request, ErrorMessage.createInvalidQueryParameter(Exceptions.toMessageString(e)));
- }
-
private HttpResponse illegalQueryResponse(HttpRequest request, RuntimeException e) {
return errorResponse(request, ErrorMessage.createIllegalQuery(Exceptions.toMessageString(e)));
}
@@ -275,7 +268,6 @@ public class SearchHandler extends LoggingRequestHandler {
return errorResponse(request, ErrorMessage.createInternalServerError(Exceptions.toMessageString(e)));
}
-
private HttpSearchResponse handleBody(HttpRequest request) {
Map<String, String> requestMap = requestMapFromRequest(request);
@@ -450,19 +442,15 @@ public class SearchHandler extends LoggingRequestHandler {
+ Exceptions.toMessageString(e));
log.log(Level.FINE, error::getDetailedMessage);
return new Result(query, error);
+ } catch (IllegalInputException e) {
+ ErrorMessage error = ErrorMessage.createBadRequest("Invalid request [" + request + "]: "
+ + Exceptions.toMessageString(e));
+ log.log(Level.FINE, error::getDetailedMessage);
+ return new Result(query, error);
} catch (IllegalArgumentException e) {
- if ("Comparison method violates its general contract!".equals(e.getMessage())) {
- // This is an error in application components or Vespa code
- log(request, query, e);
- return new Result(query, ErrorMessage.createUnspecifiedError("Failed searching: " +
- Exceptions.toMessageString(e), e));
- }
- else {
- ErrorMessage error = ErrorMessage.createBadRequest("Invalid search request [" + request + "]: "
- + Exceptions.toMessageString(e));
- log.log(Level.FINE, error::getDetailedMessage);
- return new Result(query, error);
- }
+ log(request, query, e);
+ return new Result(query, ErrorMessage.createUnspecifiedError("Failed: " +
+ Exceptions.toMessageString(e), e));
} catch (LinkageError | StackOverflowError e) {
// LinkageError should have been an Exception in an OSGi world - typical bundle dependency issue problem
// StackOverflowError is recoverable
@@ -472,7 +460,7 @@ public class SearchHandler extends LoggingRequestHandler {
return new Result(query, error);
} catch (Exception e) {
log(request, query, e);
- return new Result(query, ErrorMessage.createUnspecifiedError("Failed searching: " +
+ return new Result(query, ErrorMessage.createUnspecifiedError("Failed: " +
Exceptions.toMessageString(e), e));
}
}
@@ -579,8 +567,8 @@ public class SearchHandler extends LoggingRequestHandler {
byte[] byteArray = IOUtils.readBytes(request.getData(), 1 << 20);
inspector = SlimeUtils.jsonToSlime(byteArray).get();
if (inspector.field("error_message").valid()) {
- throw new QueryException("Illegal query: " + inspector.field("error_message").asString() + " at: '" +
- new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8) + "'");
+ throw new IllegalInputException("Illegal query: " + inspector.field("error_message").asString() + " at: '" +
+ new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8) + "'");
}
} catch (IOException e) {
@@ -593,9 +581,9 @@ public class SearchHandler extends LoggingRequestHandler {
requestMap.putAll(request.propertyMap());
if (requestMap.containsKey("yql") && (requestMap.containsKey("select.where") || requestMap.containsKey("select.grouping")) )
- throw new QueryException("Illegal query: Query contains both yql and select parameter");
+ throw new IllegalInputException("Illegal query: Query contains both yql and select parameter");
if (requestMap.containsKey("query") && (requestMap.containsKey("select.where") || requestMap.containsKey("select.grouping")) )
- throw new QueryException("Illegal query: Query contains both query and select parameter");
+ throw new IllegalInputException("Illegal query: Query contains both query and select parameter");
return requestMap;
}
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/PageTemplateSearcher.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/PageTemplateSearcher.java
index 0ec04bf99de..2074fce19bd 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/PageTemplateSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/PageTemplateSearcher.java
@@ -2,9 +2,9 @@
package com.yahoo.search.pagetemplates;
import com.google.inject.Inject;
-import com.yahoo.component.ComponentId;
import com.yahoo.component.chain.dependencies.Provides;
import com.yahoo.component.provider.ComponentRegistry;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
@@ -13,8 +13,6 @@ import com.yahoo.search.pagetemplates.config.PageTemplateConfigurer;
import com.yahoo.search.pagetemplates.engine.Organizer;
import com.yahoo.search.pagetemplates.engine.Resolution;
import com.yahoo.search.pagetemplates.engine.Resolver;
-import com.yahoo.search.pagetemplates.engine.resolvers.DeterministicResolver;
-import com.yahoo.search.pagetemplates.engine.resolvers.RandomResolver;
import com.yahoo.search.pagetemplates.engine.resolvers.ResolverRegistry;
import com.yahoo.search.pagetemplates.model.Choice;
import com.yahoo.search.pagetemplates.model.PageElement;
@@ -23,7 +21,13 @@ import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.searchchain.Execution;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Map;
/**
* Enables page optimization templates.
@@ -107,7 +111,7 @@ public class PageTemplateSearcher extends Searcher {
@Override
public Result search(Query query, Execution execution) {
// Pre execution: Choose template and sources
- List<PageElement> pages=selectPageTemplates(query);
+ List<PageElement> pages = selectPageTemplates(query);
if (pages.isEmpty()) return execution.search(query); // Bypass if no page template chosen
addSources(pages,query);
@@ -115,12 +119,12 @@ public class PageTemplateSearcher extends Searcher {
query.properties().set(pagePageTemplateListName, pages);
// Execute
- Result result=execution.search(query);
+ Result result = execution.search(query);
// Post execution: Resolve choices and organize the result as dictated by the resolved template
- Choice pageTemplateChoice=Choice.createSingletons(pages);
- Resolution resolution=selectResolver(query).resolve(pageTemplateChoice,query,result);
- organizer.organize(pageTemplateChoice,resolution,result);
+ Choice pageTemplateChoice = Choice.createSingletons(pages);
+ Resolution resolution = selectResolver(query).resolve(pageTemplateChoice, query, result);
+ organizer.organize(pageTemplateChoice, resolution, result);
return result;
}
@@ -132,23 +136,23 @@ public class PageTemplateSearcher extends Searcher {
// Determine the list of page template ids
@SuppressWarnings("unchecked")
List<String> pageIds = (List<String>) query.properties().get(pageIdListName);
- if (pageIds==null) {
- String pageIdString=query.properties().getString(pageIdName,"").trim();
- if (pageIdString.length()>0)
- pageIds=Arrays.asList(pageIdString.split(" "));
+ if (pageIds == null) {
+ String pageIdString = query.properties().getString(pageIdName,"").trim();
+ if (pageIdString.length() > 0)
+ pageIds = Arrays.asList(pageIdString.split(" "));
}
// If none set, just return the default or null if none
- if (pageIds==null) {
+ if (pageIds == null) {
PageElement defaultPage=templateRegistry.getComponent("default");
- return (defaultPage==null ? Collections.<PageElement>emptyList() : Collections.singletonList(defaultPage));
+ return (defaultPage == null ? Collections.<PageElement>emptyList() : Collections.singletonList(defaultPage));
}
// Resolve the id list to page templates
- List<PageElement> pages=new ArrayList<>(pageIds.size());
+ List<PageElement> pages = new ArrayList<>(pageIds.size());
for (String pageId : pageIds) {
- PageTemplate page=templateRegistry.getComponent(pageId);
- if (page==null)
+ PageTemplate page = templateRegistry.getComponent(pageId);
+ if (page == null)
query.errors().add(ErrorMessage.createInvalidQueryParameter("Could not resolve requested page template '" +
pageId + "'"));
else
@@ -159,17 +163,17 @@ public class PageTemplateSearcher extends Searcher {
}
private Resolver selectResolver(Query query) {
- String resolverId=query.properties().getString(pageResolverName);
- if (resolverId==null) return resolverRegistry.defaultResolver();
- Resolver resolver=resolverRegistry.getComponent(resolverId);
- if (resolver==null) throw new IllegalArgumentException("No page template resolver '" + resolverId + "'");
+ String resolverId = query.properties().getString(pageResolverName);
+ if (resolverId == null) return resolverRegistry.defaultResolver();
+ Resolver resolver = resolverRegistry.getComponent(resolverId);
+ if (resolver == null) throw new IllegalInputException("No page template resolver '" + resolverId + "'");
return resolver;
}
/** Sets query.getModel().getSources() to the right value and add source parameters specified in templates */
- private void addSources(List<PageElement> pages,Query query) {
+ private void addSources(List<PageElement> pages, Query query) {
// Determine all wanted sources
- Set<Source> pageSources=new HashSet<>();
+ Set<Source> pageSources = new HashSet<>();
for (PageElement page : pages)
pageSources.addAll(((PageTemplate)page).getSources());
@@ -177,34 +181,34 @@ public class PageTemplateSearcher extends Searcher {
if (query.getModel().getSources().size() > 0) {
// Add properties if the source list is set explicitly, but do not modify otherwise
- addParametersForIncludedSources(pageSources,query);
+ addParametersForIncludedSources(pageSources, query);
return;
}
if (pageSources.contains(Source.any)) {
- IntentModel intentModel=IntentModel.getFrom(query);
- if (intentModel!=null) {
+ IntentModel intentModel = IntentModel.getFrom(query);
+ if (intentModel != null) {
query.getModel().getSources().addAll(intentModel.getSourceNames());
- addPageTemplateSources(pageSources,query);
+ addPageTemplateSources(pageSources, query);
}
// otherwise leave empty to search all
}
else { // Let the page templates decide
- addPageTemplateSources(pageSources,query);
+ addPageTemplateSources(pageSources, query);
}
}
private void addPageTemplateSources(Set<Source> pageSources,Query query) {
for (Source pageSource : pageSources) {
- if (pageSource==Source.any) continue;
+ if (pageSource == Source.any) continue;
query.getModel().getSources().add(pageSource.getName());
addParameters(pageSource,query);
}
}
- private void addParametersForIncludedSources(Set<Source> sources,Query query) {
+ private void addParametersForIncludedSources(Set<Source> sources, Query query) {
for (Source source : sources) {
- if (source.parameters().size()>0 && query.getModel().getSources().contains(source.getName()))
+ if (source.parameters().size() > 0 && query.getModel().getSources().contains(source.getName()))
addParameters(source,query);
}
}
@@ -220,8 +224,8 @@ public class PageTemplateSearcher extends Searcher {
* is not supported. (Same parameter sets in multiple templates is supported,
* and will be just one entry in this set).
*/
- private void addErrorIfSameSourceMultipleTimes(List<PageElement> pages,Set<Source> sources,Query query) {
- Set<String> sourceNames=new HashSet<>();
+ private void addErrorIfSameSourceMultipleTimes(List<PageElement> pages, Set<Source> sources, Query query) {
+ Set<String> sourceNames = new HashSet<>();
for (Source source : sources) {
if (sourceNames.contains(source.getName()))
query.errors().add(ErrorMessage.createInvalidQueryParameter(
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderMappingVisitor.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderMappingVisitor.java
index c29e9615fe8..c37ea5667c0 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderMappingVisitor.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderMappingVisitor.java
@@ -19,16 +19,16 @@ import java.util.Map;
*/
class PlaceholderMappingVisitor extends PageTemplateVisitor {
- private Map<String, MapChoice> placeholderIdToChoice=new LinkedHashMap<>();
+ private final Map<String, MapChoice> placeholderIdToChoice = new LinkedHashMap<>();
@Override
public void visit(MapChoice mapChoice) {
- List<String> placeholderIds=mapChoice.placeholderIds();
+ List<String> placeholderIds = mapChoice.placeholderIds();
for (String placeholderId : placeholderIds) {
- MapChoice existingChoice=placeholderIdToChoice.put(placeholderId,mapChoice);
- if (existingChoice!=null)
+ MapChoice existingChoice = placeholderIdToChoice.put(placeholderId,mapChoice);
+ if (existingChoice != null)
throw new IllegalArgumentException("placeholder id '" + placeholderId + "' is referenced by both " +
- mapChoice + " and " + existingChoice + ": Only one reference is allowed");
+ mapChoice + " and " + existingChoice + ": Only one reference is allowed");
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderReferenceCreatingVisitor.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderReferenceCreatingVisitor.java
index e8870f4f11a..5ef507201cb 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderReferenceCreatingVisitor.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/PlaceholderReferenceCreatingVisitor.java
@@ -1,9 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.pagetemplates;
-import com.yahoo.search.pagetemplates.model.*;
+import com.yahoo.search.pagetemplates.model.MapChoice;
+import com.yahoo.search.pagetemplates.model.PageTemplateVisitor;
+import com.yahoo.search.pagetemplates.model.Placeholder;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -14,16 +15,16 @@ import java.util.Map;
*/
class PlaceholderReferenceCreatingVisitor extends PageTemplateVisitor {
- private Map<String, MapChoice> placeholderIdToChoice=new HashMap<>();
+ private final Map<String, MapChoice> placeholderIdToChoice;
public PlaceholderReferenceCreatingVisitor(Map<String, MapChoice> placeholderIdToChoice) {
- this.placeholderIdToChoice=placeholderIdToChoice;
+ this.placeholderIdToChoice = placeholderIdToChoice;
}
@Override
public void visit(Placeholder placeholder) {
- MapChoice choice=placeholderIdToChoice.get(placeholder.getId());
- if (choice==null)
+ MapChoice choice = placeholderIdToChoice.get(placeholder.getId());
+ if (choice == null)
throw new IllegalArgumentException(placeholder + " is not referenced by any choice");
placeholder.setValueContainer(choice);
}
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/config/PageTemplateXMLReader.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/config/PageTemplateXMLReader.java
index beffd12b22a..0359432a819 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/config/PageTemplateXMLReader.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/config/PageTemplateXMLReader.java
@@ -38,18 +38,18 @@ public class PageTemplateXMLReader {
* @throws RuntimeException if <code>directory</code> is not a readable directory, or if there is some error in the XML
*/
public PageTemplateRegistry read(String directory) {
- List<NamedReader> pageReaders=new ArrayList<>();
+ List<NamedReader> pageReaders = new ArrayList<>();
try {
- File dir=new File(directory);
- if ( !dir.isDirectory() ) throw new IllegalArgumentException("Could not read page templates: '" +
- directory + "' is not a valid directory.");
+ File dir = new File(directory);
+ if ( ! dir.isDirectory() ) throw new IllegalArgumentException("Could not read page templates: '" +
+ directory + "' is not a valid directory.");
for (File file : sortFiles(dir)) {
if ( ! file.getName().endsWith(".xml")) continue;
- pageReaders.add(new NamedReader(file.getName(),new FileReader(file)));
+ pageReaders.add(new NamedReader(file.getName(), new FileReader(file)));
}
- return read(pageReaders,true);
+ return read(pageReaders, true);
}
catch (IOException e) {
throw new IllegalArgumentException("Could not read page templates from '" + directory + "'",e);
@@ -67,18 +67,18 @@ public class PageTemplateXMLReader {
* @throws RuntimeException if <code>fileName</code> is not a readable file, or if there is some error in the XML
*/
public PageTemplate readFile(String fileName) {
- NamedReader pageReader=null;
+ NamedReader pageReader = null;
try {
- File file=new File(fileName);
- pageReader=new NamedReader(fileName,new FileReader(file));
- String firstName=file.getName().substring(0,file.getName().length()-4);
- return read(Collections.singletonList(pageReader),true).getComponent(firstName);
+ File file = new File(fileName);
+ pageReader = new NamedReader(fileName,new FileReader(file));
+ String firstName = file.getName().substring(0, file.getName().length() - 4);
+ return read(Collections.singletonList(pageReader), true).getComponent(firstName);
}
catch (IOException e) {
- throw new IllegalArgumentException("Could not read the page template '" + fileName + "'",e);
+ throw new IllegalArgumentException("Could not read the page template '" + fileName + "'", e);
}
finally {
- if (pageReader!=null)
+ if (pageReader != null)
try { pageReader.close(); } catch (IOException e) { }
}
}
@@ -130,11 +130,11 @@ public class PageTemplateXMLReader {
}
/** Throws an exception if the name is not corresponding to the id */
- private void validateFileName(final String actualName,ComponentId id,String artifactName) {
- String expectedCanonicalFileName=id.toFileName();
- String fileName=new File(actualName).getName();
- fileName=stripXmlEnding(fileName);
- String canonicalFileName=ComponentId.fromFileName(fileName).toFileName();
+ private void validateFileName(String actualName, ComponentId id, String artifactName) {
+ String expectedCanonicalFileName = id.toFileName();
+ String fileName = new File(actualName).getName();
+ fileName = stripXmlEnding(fileName);
+ String canonicalFileName = ComponentId.fromFileName(fileName).toFileName();
if ( ! canonicalFileName.equals(expectedCanonicalFileName))
throw new IllegalArgumentException("The file name of " + artifactName + " '" + id +
"' must be '" + expectedCanonicalFileName + ".xml' but was '" + actualName + "'");
@@ -144,14 +144,14 @@ public class PageTemplateXMLReader {
if (!fileName.endsWith(".xml"))
throw new IllegalArgumentException("'" + fileName + "' should have a .xml ending");
else
- return fileName.substring(0,fileName.length()-4);
+ return fileName.substring(0, fileName.length() - 4);
}
private void readPages() {
for (Map.Entry<ComponentId,Element> pageElement : pageElementsByPageId.entrySet()) {
try {
- PageTemplate page=registry.getComponent(pageElement.getValue().getAttribute("id"));
- readPageContent(pageElement.getValue(),page);
+ PageTemplate page = registry.getComponent(pageElement.getValue().getAttribute("id"));
+ readPageContent(pageElement.getValue(), page);
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Could not read page template '" + pageElement.getKey() + "'",e);
@@ -159,16 +159,16 @@ public class PageTemplateXMLReader {
}
}
- private void readPageContent(Element pageElement,PageTemplate page) {
+ private void readPageContent(Element pageElement, PageTemplate page) {
if (page.isFrozen()) return; // Already read
- Section rootSection=new Section(page.getId().toString());
- readSection(pageElement,rootSection);
+ Section rootSection = new Section(page.getId().toString());
+ readSection(pageElement, rootSection);
page.setSection(rootSection);
page.freeze();
}
/** Fills a section with attributes and sub-elements from a "section" or "page" element */
- private Section readSection(Element sectionElement,Section section) {
+ private Section readSection(Element sectionElement, Section section) {
section.setLayout(Layout.fromString(sectionElement.getAttribute("layout")));
section.setRegion(sectionElement.getAttribute("region"));
section.setOrder(Sorting.fromString(sectionElement.getAttribute("order")));
@@ -198,10 +198,10 @@ public class PageTemplateXMLReader {
/** Reads the direct descendant elements of an include */
private List<PageElement> readInclude(Element element) {
- PageTemplate included=registry.getComponent(element.getAttribute("idref"));
- if (included==null)
+ PageTemplate included = registry.getComponent(element.getAttribute("idref"));
+ if (included == null)
throw new IllegalArgumentException("Could not find page template '" + element.getAttribute("idref"));
- readPageContent(pageElementsByPageId.get(included.getId()),included);
+ readPageContent(pageElementsByPageId.get(included.getId()), included);
return included.getSection().elements(Section.class);
}
@@ -223,9 +223,9 @@ public class PageTemplateXMLReader {
}
private List<Source> readSourceAttribute(Element sectionElement) {
- List<Source> sources=new ArrayList<>();
- String sourceAttributeString=sectionElement.getAttribute("source");
- if (sourceAttributeString!=null) {
+ List<Source> sources = new ArrayList<>();
+ String sourceAttributeString = sectionElement.getAttribute("source");
+ if (sourceAttributeString != null) {
for (String sourceName : sourceAttributeString.split(" ")) {
if (sourceName.isEmpty()) continue;
if ("*".equals(sourceName))
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
index 3e6e82a5584..051103cba06 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
@@ -9,9 +9,7 @@ import com.yahoo.search.query.Sorting;
import com.yahoo.search.result.*;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
/**
* Reorganizes and prunes a result as prescribed by a resolved template.
@@ -29,13 +27,13 @@ public class Organizer {
* @param result the result to organize
*/
public void organize(Choice templateChoice, Resolution resolution, Result result) {
- PageTemplate template=(PageTemplate)templateChoice.get(resolution.getResolution(templateChoice)).get(0);
- SectionHitGroup sectionGroup =toGroup(template.getSection(),resolution,result);
- ErrorHit errors=result.hits().getErrorHit();
+ PageTemplate template = (PageTemplate)templateChoice.get(resolution.getResolution(templateChoice)).get(0);
+ SectionHitGroup sectionGroup = toGroup(template.getSection(), resolution, result);
+ ErrorHit errors = result.hits().getErrorHit();
// transfer state from existing hit
sectionGroup.setQuery(result.hits().getQuery());
- if (errors!=null && errors instanceof DefaultErrorHit)
+ if (errors instanceof DefaultErrorHit)
sectionGroup.add((DefaultErrorHit)errors);
result.hits().forEachField((name, value) -> sectionGroup.setField(name, value));
result.setHits(sectionGroup);
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Resolution.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Resolution.java
index e0a3821e10c..f36ebe56e21 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Resolution.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Resolution.java
@@ -40,10 +40,10 @@ public class Resolution {
* been resolved in this
*/
public int getResolution(Choice choice) {
- if (choice.alternatives().size()==1) return 0;
+ if (choice.alternatives().size() == 1) return 0;
if (choice.isEmpty()) throw new IllegalArgumentException("Cannot return a resolution of empty " + choice);
- Integer resolution=choiceResolutions.get(choice);
- if (resolution==null) throw new IllegalArgumentException(this + " has no resolution of " + choice);
+ Integer resolution = choiceResolutions.get(choice);
+ if (resolution == null) throw new IllegalArgumentException(this + " has no resolution of " + choice);
return resolution;
}
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
index f2e2e1b034d..47914792da8 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/result/PageTemplatesXmlRenderer.java
@@ -271,10 +271,10 @@ public class PageTemplatesXmlRenderer extends AsynchronousSectionedRenderer<Resu
private Result getResult() {
try {
- return (Result) getResponse();
+ return (Result)getResponse();
} catch (ClassCastException e) {
- throw new IllegalArgumentException("PageTemplatesXmlRenderer attempted used outside a search context, got a " +
- getResponse().getClass().getName());
+ throw new IllegalStateException("PageTemplatesXmlRenderer attempted used outside a search context, got a " +
+ getResponse().getClass().getName());
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/Model.java b/container-search/src/main/java/com/yahoo/search/query/Model.java
index f06aab09a3d..637873aa375 100644
--- a/container-search/src/main/java/com/yahoo/search/query/Model.java
+++ b/container-search/src/main/java/com/yahoo/search/query/Model.java
@@ -7,6 +7,7 @@ import com.yahoo.language.LocaleFactory;
import com.yahoo.prelude.query.CompositeItem;
import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.TaggableItem;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.query.parser.Parsable;
@@ -236,10 +237,14 @@ public class Model implements Cloneable {
*/
public QueryTree getQueryTree() {
if (queryTree == null) {
- Parser parser = ParserFactory.newInstance(type, ParserEnvironment.fromExecutionContext(execution.context()));
- queryTree = parser.parse(Parsable.fromQueryModel(this));
- if (parent.getTraceLevel() >= 2) {
- parent.trace("Query parsed to: " + parent.yqlRepresentation(), 2);
+ try {
+ Parser parser = ParserFactory.newInstance(type, ParserEnvironment.fromExecutionContext(execution.context()));
+ queryTree = parser.parse(Parsable.fromQueryModel(this));
+ if (parent.getTraceLevel() >= 2)
+ parent.trace("Query parsed to: " + parent.yqlRepresentation(), 2);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalInputException("Failed parsing query", e);
}
}
return queryTree;
diff --git a/container-search/src/main/java/com/yahoo/search/query/ParameterParser.java b/container-search/src/main/java/com/yahoo/search/query/ParameterParser.java
index d358fa06977..3addc1fdb4e 100644
--- a/container-search/src/main/java/com/yahoo/search/query/ParameterParser.java
+++ b/container-search/src/main/java/com/yahoo/search/query/ParameterParser.java
@@ -1,6 +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.search.query;
+import com.yahoo.processing.IllegalInputException;
+
import static com.yahoo.container.util.Util.quote;
/**
@@ -25,13 +27,8 @@ public class ParameterParser {
* representation cannot be parsed as a number followed optionally by time unit
*/
public static Long asMilliSeconds(Object value, Long defaultValue) {
- if (value == null) {
- return defaultValue;
- }
- if (value instanceof Number) {
- Number n = (Number) value;
- return Long.valueOf(n.longValue() * 1000L);
- }
+ if (value == null) return defaultValue;
+ if (value instanceof Number) return ((Number)value).longValue() * 1000L;
return parseTime(value.toString());
}
@@ -43,7 +40,7 @@ public class ParameterParser {
double multiplier = parseUnit(time.substring(unitOffset));
return (long) (measure * multiplier);
} catch (RuntimeException e) {
- throw new IllegalArgumentException("Error parsing " + quote(time), e);
+ throw new IllegalInputException("Error parsing " + quote(time), e);
}
}
@@ -58,7 +55,7 @@ public class ParameterParser {
}
}
if (unitOffset == 0) {
- throw new NumberFormatException("Invalid number " + quote(time));
+ throw new IllegalInputException("Invalid number " + quote(time));
}
return unitOffset;
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
index 0d9acea7643..30d741f465c 100644
--- a/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
+++ b/container-search/src/main/java/com/yahoo/search/query/SelectParser.java
@@ -2,6 +2,7 @@
package com.yahoo.search.query;
import com.google.common.base.Preconditions;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.collections.LazyMap;
import com.yahoo.geo.DistanceParser;
import com.yahoo.geo.ParsedDegree;
@@ -27,7 +28,6 @@ import com.yahoo.prelude.query.OrItem;
import com.yahoo.prelude.query.PhraseItem;
import com.yahoo.prelude.query.PredicateQueryItem;
import com.yahoo.prelude.query.PrefixItem;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.prelude.query.RangeItem;
import com.yahoo.prelude.query.RankItem;
import com.yahoo.prelude.query.RegExpItem;
@@ -72,10 +72,6 @@ import static com.yahoo.search.yql.YqlParser.AND_SEGMENTING;
import static com.yahoo.search.yql.YqlParser.ANNOTATIONS;
import static com.yahoo.search.yql.YqlParser.APPROXIMATE;
import static com.yahoo.search.yql.YqlParser.ASCENDING_HITS_ORDER;
-import static com.yahoo.search.yql.YqlParser.BOUNDS;
-import static com.yahoo.search.yql.YqlParser.BOUNDS_LEFT_OPEN;
-import static com.yahoo.search.yql.YqlParser.BOUNDS_OPEN;
-import static com.yahoo.search.yql.YqlParser.BOUNDS_RIGHT_OPEN;
import static com.yahoo.search.yql.YqlParser.CONNECTION_ID;
import static com.yahoo.search.yql.YqlParser.CONNECTION_WEIGHT;
import static com.yahoo.search.yql.YqlParser.CONNECTIVITY;
@@ -83,7 +79,6 @@ import static com.yahoo.search.yql.YqlParser.DEFAULT_TARGET_NUM_HITS;
import static com.yahoo.search.yql.YqlParser.DESCENDING_HITS_ORDER;
import static com.yahoo.search.yql.YqlParser.DISTANCE;
import static com.yahoo.search.yql.YqlParser.DOT_PRODUCT;
-import static com.yahoo.search.yql.YqlParser.END_ANCHOR;
import static com.yahoo.search.yql.YqlParser.EQUIV;
import static com.yahoo.search.yql.YqlParser.FILTER;
import static com.yahoo.search.yql.YqlParser.GEO_LOCATION;
@@ -109,7 +104,6 @@ import static com.yahoo.search.yql.YqlParser.RANKED;
import static com.yahoo.search.yql.YqlParser.SAME_ELEMENT;
import static com.yahoo.search.yql.YqlParser.SCORE_THRESHOLD;
import static com.yahoo.search.yql.YqlParser.SIGNIFICANCE;
-import static com.yahoo.search.yql.YqlParser.START_ANCHOR;
import static com.yahoo.search.yql.YqlParser.STEM;
import static com.yahoo.search.yql.YqlParser.SUBSTRING;
import static com.yahoo.search.yql.YqlParser.SUFFIX;
@@ -117,7 +111,6 @@ import static com.yahoo.search.yql.YqlParser.TARGET_HITS;
import static com.yahoo.search.yql.YqlParser.TARGET_NUM_HITS;
import static com.yahoo.search.yql.YqlParser.THRESHOLD_BOOST_FACTOR;
import static com.yahoo.search.yql.YqlParser.UNIQUE_ID;
-import static com.yahoo.search.yql.YqlParser.URI;
import static com.yahoo.search.yql.YqlParser.USE_POSITION_DATA;
import static com.yahoo.search.yql.YqlParser.USER_INPUT_LANGUAGE;
import static com.yahoo.search.yql.YqlParser.WAND;
@@ -169,13 +162,18 @@ public class SelectParser implements Parser {
private QueryTree buildTree() {
Inspector inspector = SlimeUtils.jsonToSlime(this.query.getSelect().getWhereString()).get();
if (inspector.field("error_message").valid()) {
- throw new QueryException("Illegal query: " + inspector.field("error_message").asString() +
+ throw new IllegalInputException("Illegal query: " + inspector.field("error_message").asString() +
" at: '" + new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8) + "'");
}
- Item root = walkJson(inspector);
- connectItems();
- return new QueryTree(root);
+ try {
+ Item root = walkJson(inspector);
+ connectItems();
+ return new QueryTree(root);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalInputException("Illegal JSON query", e);
+ }
}
private Item walkJson(Inspector inspector) {
@@ -229,8 +227,8 @@ public class SelectParser implements Parser {
private List<String> toGroupingRequests(String groupingJson) {
Inspector inspector = SlimeUtils.jsonToSlime(groupingJson).get();
if (inspector.field("error_message").valid()) {
- throw new QueryException("Illegal query: " + inspector.field("error_message").asString() +
- " at: '" + new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8) + "'");
+ throw new IllegalInputException("Illegal query: " + inspector.field("error_message").asString() +
+ " at: '" + new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8) + "'");
}
List<String> operations = new ArrayList<>();
@@ -1199,9 +1197,10 @@ public class SelectParser implements Parser {
private void connectItems() {
for (ConnectedItem entry : connectedItems) {
TaggableItem to = identifiedItems.get(entry.toId);
- Preconditions.checkNotNull(to,
- "Item '%s' was specified to connect to item with ID %s, which does not "
- + "exist in the query.", entry.fromItem, entry.toId);
+ if (to == null)
+ throw new IllegalArgumentException("Item '" + entry.fromItem +
+ "' was specified to connect to item with ID " + entry.toId +
+ ", which does not exist in the query.");
entry.fromItem.setConnectivity((Item) to, entry.weight);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/Sorting.java b/container-search/src/main/java/com/yahoo/search/query/Sorting.java
index 6518dcd5b6d..0a0ae65d524 100644
--- a/container-search/src/main/java/com/yahoo/search/query/Sorting.java
+++ b/container-search/src/main/java/com/yahoo/search/query/Sorting.java
@@ -3,6 +3,7 @@ package com.yahoo.search.query;
import com.ibm.icu.text.Collator;
import com.ibm.icu.util.ULocale;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.text.Utf8;
import java.nio.ByteBuffer;
@@ -88,7 +89,7 @@ public class Sorting implements Cloneable {
} else if (STRENGTH_IDENTICAL.equalsIgnoreCase(s)) {
strength = UcaSorter.Strength.IDENTICAL;
} else {
- throw new IllegalArgumentException("Unknown collation strength: '" + s + "'");
+ throw new IllegalInputException("Unknown collation strength: '" + s + "'");
}
sorter = new UcaSorter(sortString.substring(startPar+1, commaPos), sortString.substring(commaPos+1, commaopt), strength);
} else {
@@ -99,9 +100,9 @@ public class Sorting implements Cloneable {
}
} else {
if (funcName.isEmpty()) {
- throw new IllegalArgumentException("No sort function specified");
+ throw new IllegalInputException("No sort function specified");
} else {
- throw new IllegalArgumentException("Unknown sort function '" + funcName + "'");
+ throw new IllegalInputException("Unknown sort function '" + funcName + "'");
}
}
} else {
@@ -196,7 +197,7 @@ public class Sorting implements Cloneable {
if (legalAttributeName.matcher(fieldName).matches()) {
this.fieldName = fieldName;
} else {
- throw new IllegalArgumentException("Illegal attribute name '" + fieldName + "' for sorting. Requires '" + legalAttributeName.pattern() + "'");
+ throw new IllegalInputException("Illegal attribute name '" + fieldName + "' for sorting. Requires '" + legalAttributeName.pattern() + "'");
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
index b6b03d37da8..6008b046d1a 100644
--- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
+++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfile.java
@@ -4,6 +4,7 @@ package com.yahoo.search.query.profile;
import com.google.common.collect.ImmutableList;
import com.yahoo.component.ComponentId;
import com.yahoo.component.provider.FreezableSimpleComponent;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.processing.request.Properties;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfile;
@@ -451,7 +452,7 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable
setNode(name, value, null, binding, registry);
}
catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Could not set '" + name + "' to '" + value + "'", e);
+ throw new IllegalInputException("Could not set '" + name + "' to '" + value + "'", e);
}
}
@@ -688,15 +689,15 @@ public class QueryProfile extends FreezableSimpleComponent implements Cloneable
FieldDescription fieldDescription = type.getField(localName);
if (fieldDescription == null) {
if (type.isStrict())
- throw new IllegalArgumentException("'" + localName + "' is not declared in " + type + ", and the type is strict");
+ throw new IllegalInputException("'" + localName + "' is not declared in " + type + ", and the type is strict");
return value;
}
if (registry == null && (fieldDescription.getType() instanceof QueryProfileFieldType))
- throw new IllegalArgumentException("A registry was not passed: Query profile references is not supported");
+ throw new IllegalInputException("A registry was not passed: Query profile references is not supported");
Object convertedValue = fieldDescription.getType().convertFrom(value, registry);
if (convertedValue == null)
- throw new IllegalArgumentException("'" + value + "' is not a " + fieldDescription.getType().toInstanceDescription());
+ throw new IllegalInputException("'" + value + "' is not a " + fieldDescription.getType().toInstanceDescription());
return convertedValue;
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java
index d199ee44c9c..41272d695ac 100644
--- a/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java
+++ b/container-search/src/main/java/com/yahoo/search/query/profile/QueryProfileProperties.java
@@ -2,6 +2,7 @@
package com.yahoo.search.query.profile;
import com.yahoo.collections.Pair;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.processing.request.properties.PropertyMap;
import com.yahoo.protect.Validator;
@@ -107,7 +108,7 @@ public class QueryProfileProperties extends Properties {
String localName = name.get(i);
FieldDescription fieldDescription = type.getField(localName);
if (fieldDescription == null && type.isStrict())
- throw new IllegalArgumentException("'" + localName + "' is not declared in " + type + ", and the type is strict");
+ throw new IllegalInputException("'" + localName + "' is not declared in " + type + ", and the type is strict");
// TODO: In addition to strictness, check legality along the way
@@ -115,7 +116,7 @@ public class QueryProfileProperties extends Properties {
if (i == name.size() - 1) { // at the end of the path, check the assignment type
value = fieldDescription.getType().convertFrom(value, profile.getRegistry());
if (value == null)
- throw new IllegalArgumentException("'" + value + "' is not a " +
+ throw new IllegalInputException("'" + value + "' is not a " +
fieldDescription.getType().toInstanceDescription());
}
else if (fieldDescription.getType() instanceof QueryProfileFieldType) {
@@ -129,12 +130,12 @@ public class QueryProfileProperties extends Properties {
if (value instanceof String && value.toString().startsWith("ref:")) {
if (profile.getRegistry() == null)
- throw new IllegalArgumentException("Runtime query profile references does not work when the " +
+ throw new IllegalInputException("Runtime query profile references does not work when the " +
"QueryProfileProperties are constructed without a registry");
String queryProfileId = value.toString().substring(4);
value = profile.getRegistry().findQueryProfile(queryProfileId);
if (value == null)
- throw new IllegalArgumentException("Query profile '" + queryProfileId + "' is not found");
+ throw new IllegalInputException("Query profile '" + queryProfileId + "' is not found");
}
if (value instanceof CompiledQueryProfile) { // this will be due to one of the two clauses above
@@ -149,7 +150,7 @@ public class QueryProfileProperties extends Properties {
}
}
catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Could not set '" + name + "' to '" + value + "'", e);
+ throw new IllegalInputException("Could not set '" + name + "' to '" + value + "'", e);
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/Binding.java b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/Binding.java
index 8638a99172f..e873c80add1 100644
--- a/container-search/src/main/java/com/yahoo/search/query/profile/compiled/Binding.java
+++ b/container-search/src/main/java/com/yahoo/search/query/profile/compiled/Binding.java
@@ -33,7 +33,6 @@ public class Binding implements Comparable<Binding> {
private final int hashCode;
- @SuppressWarnings("unchecked")
public static final Binding nullBinding = new Binding(Integer.MAX_VALUE, Collections.<String,String>emptyMap());
public static Binding createFrom(DimensionBinding dimensionBinding) {
diff --git a/container-search/src/main/java/com/yahoo/search/query/profile/types/FieldDescription.java b/container-search/src/main/java/com/yahoo/search/query/profile/types/FieldDescription.java
index 6c30f1a8b05..daab5f6a378 100644
--- a/container-search/src/main/java/com/yahoo/search/query/profile/types/FieldDescription.java
+++ b/container-search/src/main/java/com/yahoo/search/query/profile/types/FieldDescription.java
@@ -97,7 +97,8 @@ public class FieldDescription implements Comparable<FieldDescription> {
this.type = type;
// Forbidden until we can figure out the right semantics
- if (name.isCompound() && ! aliases.isEmpty()) throw new IllegalArgumentException("Aliases are not allowed with compound names");
+ if (name.isCompound() && ! aliases.isEmpty())
+ throw new IllegalArgumentException("Aliases are not allowed with compound names");
this.aliases = ImmutableList.copyOf(aliases);
this.mandatory = mandatory;
diff --git a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
index d5f88ba99ec..6186f588a21 100644
--- a/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
+++ b/container-search/src/main/java/com/yahoo/search/query/properties/QueryProperties.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query.properties;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
@@ -317,7 +318,7 @@ public class QueryProperties extends Properties {
if (e.getMessage() != null && e.getMessage().startsWith("Could not set"))
throw e;
else
- throw new IllegalArgumentException("Could not set '" + key + "' to '" + value + "'", e);
+ throw new IllegalInputException("Could not set '" + key + "' to '" + value + "'", e);
}
}
@@ -364,8 +365,8 @@ public class QueryProperties extends Properties {
}
private void throwIllegalParameter(String key,String namespace) {
- throw new IllegalArgumentException("'" + key + "' is not a valid property in '" + namespace +
- "'. See the query api for valid keys starting by '" + namespace + "'.");
+ throw new IllegalInputException("'" + key + "' is not a valid property in '" + namespace +
+ "'. See the query api for valid keys starting by '" + namespace + "'.");
}
@Override
diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java b/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
index 794247863bf..72a6533e946 100644
--- a/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
+++ b/container-search/src/main/java/com/yahoo/search/query/ranking/MatchPhase.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query.ranking;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.profile.types.FieldDescription;
@@ -84,8 +85,9 @@ public class MatchPhase implements Cloneable {
public void setMaxFilterCoverage(double maxFilterCoverage) {
if ((maxFilterCoverage < 0.0) || (maxFilterCoverage > 1.0)) {
- throw new IllegalArgumentException("maxFilterCoverage must be in the range [0.0, 1.0]. It is " + maxFilterCoverage);
+ throw new IllegalInputException("maxFilterCoverage must be in the range [0.0, 1.0]. It is " + maxFilterCoverage);
}
+
this.maxFilterCoverage = maxFilterCoverage;
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java b/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java
index fb3f2acfadd..14e4e006b39 100644
--- a/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java
+++ b/container-search/src/main/java/com/yahoo/search/query/ranking/Matching.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query.ranking;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.profile.types.FieldDescription;
import com.yahoo.search.query.profile.types.QueryProfileType;
@@ -59,7 +60,7 @@ public class Matching implements Cloneable {
public void setTermwiselimit(double value) {
if ((value < 0.0) || (value > 1.0)) {
- throw new IllegalArgumentException("termwiselimit must be in the range [0.0, 1.0]. It is " + value);
+ throw new IllegalInputException("termwiselimit must be in the range [0.0, 1.0]. It is " + value);
}
termwiseLimit = value;
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java
index 0d47ef77ce5..43c26692221 100644
--- a/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java
+++ b/container-search/src/main/java/com/yahoo/search/query/ranking/SoftTimeout.java
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query.ranking;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.query.Ranking;
import com.yahoo.search.query.profile.types.FieldDescription;
@@ -54,7 +55,7 @@ public class SoftTimeout implements Cloneable {
/** Override the adaptive factor determined on the content nodes */
public void setFactor(double factor) {
if ((factor < 0.0) || (factor > 1.0)) {
- throw new IllegalArgumentException("factor must be in the range [0.0, 1.0], got " + factor);
+ throw new IllegalInputException("factor must be in the range [0.0, 1.0], got " + factor);
}
this.factor = factor;
}
@@ -64,7 +65,7 @@ public class SoftTimeout implements Cloneable {
/** Override the tail cost factor determined on the content nodes */
public void setTailcost(double tailcost) {
if ((tailcost < 0.0) || (tailcost > 1.0)) {
- throw new IllegalArgumentException("tailcost must be in the range [0.0, 1.0], got " + tailcost);
+ throw new IllegalInputException("tailcost must be in the range [0.0, 1.0], got " + tailcost);
}
this.tailcost = tailcost;
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/rewrite/rewriters/GenericExpansionRewriter.java b/container-search/src/main/java/com/yahoo/search/query/rewrite/rewriters/GenericExpansionRewriter.java
index 794217e688f..9a2374da4c9 100644
--- a/container-search/src/main/java/com/yahoo/search/query/rewrite/rewriters/GenericExpansionRewriter.java
+++ b/container-search/src/main/java/com/yahoo/search/query/rewrite/rewriters/GenericExpansionRewriter.java
@@ -76,9 +76,8 @@ public class GenericExpansionRewriter extends QueryRewriteSearcher {
HashMap<String, File> fileList) {
logger = Logger.getLogger(GenericExpansionRewriter.class.getName());
FSA fsa = (FSA)rewriterDicts.get(GENERIC_EXPAND_DICT);
- if(fsa==null) {
- RewriterUtils.error(logger, "Error retrieving FSA dictionary: " +
- GENERIC_EXPAND_DICT);
+ if (fsa==null) {
+ RewriterUtils.error(logger, "Error retrieving FSA dictionary: " + GENERIC_EXPAND_DICT);
return false;
}
// Create Phrase Matcher
diff --git a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/ItemContext.java b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/ItemContext.java
index e739608387d..b6c886c91d7 100644
--- a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/ItemContext.java
+++ b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/ItemContext.java
@@ -12,6 +12,7 @@ import java.util.Map;
* @author Tony Vaagenes
*/
public class ItemContext {
+
private class Connectivity {
final String id;
final double strength;
@@ -43,7 +44,8 @@ public class ItemContext {
private Item getItem(String id) {
Item item = itemById.get(id);
if (item == null)
- throw new IllegalArgumentException("No item with id '" + id + "'.");
+ throw new IllegalArgumentException("No item with id '" + id + "'");
return item;
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TermConverter.java b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TermConverter.java
index 04c01d7acc1..503987af027 100644
--- a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TermConverter.java
+++ b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TermConverter.java
@@ -10,6 +10,7 @@ import com.yahoo.search.query.textserialize.serializer.ItemIdMapper;
* @author Tony Vaagenes
*/
public abstract class TermConverter implements ItemFormConverter {
+
@Override
public Object formToItem(String name, ItemArguments arguments, ItemContext context) {
ensureOnlyOneChild(arguments);
@@ -22,7 +23,6 @@ public abstract class TermConverter implements ItemFormConverter {
abstract TermItem newTermItem(String word);
-
private void ensureOnlyOneChild(ItemArguments arguments) {
if (arguments.children.size() != 1) {
throw new IllegalArgumentException("Expected exactly one argument, got '" +
@@ -50,4 +50,5 @@ public abstract class TermConverter implements ItemFormConverter {
}
protected abstract String getValue(TermItem item);
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TypeCheck.java b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TypeCheck.java
index b7843a300dc..70eba9d8b50 100644
--- a/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TypeCheck.java
+++ b/container-search/src/main/java/com/yahoo/search/query/textserialize/item/TypeCheck.java
@@ -7,6 +7,7 @@ import com.yahoo.protect.Validator;
* @author Tony Vaagenes
*/
public class TypeCheck {
+
public static void ensureInstanceOf(Object object, Class<?> c) {
Validator.ensureInstanceOf(expectationString(c.getName(), object.getClass().getSimpleName()),
object, c);
@@ -24,4 +25,5 @@ public class TypeCheck {
private static String expectationString(String expected, String got) {
return "Expected " + expected + ", but got " + got;
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/query/textserialize/serializer/Serializer.java b/container-search/src/main/java/com/yahoo/search/query/textserialize/serializer/Serializer.java
index d4e499bab79..d849e744184 100644
--- a/container-search/src/main/java/com/yahoo/search/query/textserialize/serializer/Serializer.java
+++ b/container-search/src/main/java/com/yahoo/search/query/textserialize/serializer/Serializer.java
@@ -14,6 +14,7 @@ import static com.yahoo.search.query.textserialize.item.ListUtil.first;
* @author Tony Vaagenes
*/
class Serializer {
+
static String serialize(Object child, ItemIdMapper itemIdMapper) {
if (child instanceof DispatchForm) {
return ((DispatchForm) child).serialize(itemIdMapper);
@@ -76,4 +77,5 @@ class Serializer {
static String serializeItem(Item item, ItemIdMapper itemIdMapper) {
return ItemExecutorRegistry.getByType(item.getItemType()).itemToForm(item, itemIdMapper).serialize(itemIdMapper);
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanAttributeParser.java b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanAttributeParser.java
index fd76cc4397a..532de1270da 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanAttributeParser.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanAttributeParser.java
@@ -14,10 +14,10 @@ import java.math.BigInteger;
* a 64-bit hex number <code>0x1234</code> or a list of bits <code>[0, 2, 43,
* 22, ...]</code>.
*
- * @author <a href="mailto:magnarn@yahoo-inc.com">Magnar Nedland</a>
- * @since 5.1.15
+ * @author Magnar Nedland
*/
abstract class BooleanAttributeParser extends SimpleMapParser {
+
private boolean isMap = true;
@Override
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
index f77301f587c..de01773c27c 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/BooleanSearcher.java
@@ -4,6 +4,7 @@ package com.yahoo.search.querytransform;
import com.yahoo.component.chain.dependencies.After;
import com.yahoo.component.chain.dependencies.Provides;
import com.yahoo.prelude.query.PredicateQueryItem;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
@@ -26,6 +27,7 @@ import static com.yahoo.yolean.Exceptions.toMessageString;
@After({ STEMMING, ACCENT_REMOVAL })
@Provides(BooleanSearcher.PREDICATE)
public class BooleanSearcher extends Searcher {
+
private static final CompoundName FIELD = new CompoundName("boolean.field");
private static final CompoundName ATTRIBUTES = new CompoundName("boolean.attributes");
private static final CompoundName RANGE_ATTRIBUTES = new CompoundName("boolean.rangeAttributes");
@@ -61,7 +63,11 @@ public class BooleanSearcher extends Searcher {
} catch (TokenMgrException e) {
return new Result(query, ErrorMessage.createInvalidQueryParameter(toMessageString(e)));
}
- } else {
+ catch (IllegalArgumentException e) {
+ throw new IllegalInputException("Failed boolean search on field '" + fieldName + "'", e);
+ }
+ }
+ else {
if (query.isTraceable(5)) {
query.trace("BooleanSearcher: Nothing added to query", false, 5);
}
@@ -79,7 +85,9 @@ public class BooleanSearcher extends Searcher {
}
static public class PredicateValueAttributeParser extends BooleanAttributeParser {
- private PredicateQueryItem item;
+
+ private final PredicateQueryItem item;
+
public PredicateValueAttributeParser(PredicateQueryItem item) {
this.item = item;
}
@@ -93,10 +101,13 @@ public class BooleanSearcher extends Searcher {
protected void addAttribute(String attribute, String value, BigInteger subQueryMask) {
item.addFeature(attribute, value, subQueryMask.longValue());
}
+
}
static private class PredicateRangeAttributeParser extends BooleanAttributeParser {
- private PredicateQueryItem item;
+
+ private final PredicateQueryItem item;
+
public PredicateRangeAttributeParser(PredicateQueryItem item) {
this.item = item;
}
@@ -110,5 +121,7 @@ public class BooleanSearcher extends Searcher {
protected void addAttribute(String attribute, String value, BigInteger subQueryMask) {
item.addRangeFeature(attribute, Long.parseLong(value), subQueryMask.longValue());
}
+
}
+
}
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/WandSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/WandSearcher.java
index 0b1387a16a2..f3804af1a9e 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/WandSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/WandSearcher.java
@@ -4,6 +4,7 @@ package com.yahoo.search.querytransform;
import com.yahoo.prelude.Index;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.query.*;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
@@ -92,7 +93,7 @@ public class WandSearcher extends Searcher {
private WandType resolveWandType(IndexFacts.Session indexFacts, Query query) {
Index index = indexFacts.getIndex(fieldName);
if (index.isNull()) {
- throw new IllegalArgumentException("Field '" + fieldName + "' was not found in " + indexFacts);
+ throw new IllegalInputException("Field '" + fieldName + "' was not found in " + indexFacts);
} else {
return WandType.create(query.properties().getString(WAND_TYPE, "vespa"));
}
@@ -100,15 +101,15 @@ public class WandSearcher extends Searcher {
private int resolveHeapSize(Query query) {
String defaultHeapSize = "100";
- return Integer.valueOf(query.properties().getString(WAND_HEAP_SIZE, defaultHeapSize));
+ return Integer.parseInt(query.properties().getString(WAND_HEAP_SIZE, defaultHeapSize));
}
private double resolveScoreThreshold(Query query) {
- return Double.valueOf(query.properties().getString(WAND_SCORE_THRESHOLD, "0"));
+ return Double.parseDouble(query.properties().getString(WAND_SCORE_THRESHOLD, "0"));
}
private double resolveThresholdBoostFactor(Query query) {
- return Double.valueOf(query.properties().getString(WAND_THRESHOLD_BOOST_FACTOR, "1"));
+ return Double.parseDouble(query.properties().getString(WAND_THRESHOLD_BOOST_FACTOR, "1"));
}
public boolean hasValidData() {
@@ -166,7 +167,7 @@ public class WandSearcher extends Searcher {
} else if (inputs.getWandType().equals(WandType.DOT_PRODUCT)) {
return populate(new DotProductItem(inputs.getFieldName()), inputs.getTokens());
}
- throw new IllegalArgumentException("Unknown type '" + inputs.getWandType() + "'");
+ throw new IllegalInputException("Unknown type '" + inputs.getWandType() + "'");
}
private CompositeItem populate(CompositeItem parent, String fieldName, Map<String,Integer> tokens) {
@@ -195,10 +196,12 @@ public class WandSearcher extends Searcher {
}
private static class IntegerMapParser extends MapParser<Integer> {
+
@Override
protected Integer parseValue(String s) {
return Integer.parseInt(s);
}
+
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java b/container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java
index 783045babf4..9540bc20bc5 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java
@@ -4,6 +4,7 @@ package com.yahoo.search.rendering;
import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.provider.ComponentRegistry;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.processing.rendering.Renderer;
import com.yahoo.search.Result;
import com.yahoo.search.pagetemplates.result.PageTemplatesXmlRenderer;
@@ -103,8 +104,8 @@ public final class RendererRegistry extends ComponentRegistry<com.yahoo.processi
com.yahoo.processing.rendering.Renderer<Result> renderer = getComponent(format);
if (renderer == null)
- throw new IllegalArgumentException("No renderer with id or alias '" + format + "'. " +
- "Available renderers are: [" + rendererNames() + "].");
+ throw new IllegalInputException("No renderer with id or alias '" + format + "'. " +
+ "Available renderers are: [" + rendererNames() + "].");
return renderer;
}
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
index 62ee16993fd..f3b0cd3a61e 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/XmlRenderer.java
@@ -352,8 +352,8 @@ public final class XmlRenderer extends AsynchronousSectionedRenderer<Result> {
try {
return (Result) getResponse();
} catch (ClassCastException e) {
- throw new IllegalArgumentException("XmlRenderer attempted used outside a search context, got a " +
- getResponse().getClass().getName());
+ throw new IllegalStateException("XmlRenderer attempted used outside a search context, got a " +
+ getResponse().getClass().getName());
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
index 4c36ca9b4da..8db690678bb 100644
--- a/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
+++ b/container-search/src/main/java/com/yahoo/search/searchchain/model/federation/LocalProviderSpec.java
@@ -56,7 +56,7 @@ public class LocalProviderSpec {
this.cacheSize = cacheSize;
if (clusterName == null)
- throw new IllegalArgumentException("Missing cluster name.");
+ throw new IllegalArgumentException("Missing cluster name");
}
public static boolean includesType(String type) {
diff --git a/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java b/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
index 3c0453f8900..5e15a8ba14b 100644
--- a/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/searchers/InputCheckingSearcher.java
@@ -19,11 +19,13 @@ import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.PhraseItem;
import com.yahoo.prelude.query.TermItem;
import com.yahoo.prelude.query.WordItem;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.searchchain.Execution;
+import com.yahoo.yolean.Exceptions;
/**
* Check whether the query tree seems to be "well formed". In other words, run heurestics against
@@ -50,10 +52,8 @@ public class InputCheckingSearcher extends Searcher {
public Result search(Query query, Execution execution) {
try {
checkQuery(query);
- } catch (IllegalArgumentException e) {
- if (log.isLoggable(Level.FINE)) {
- log.log(Level.FINE, "Rejected query \"" + query.toString() + "\" on cause of: " + e.getMessage());
- }
+ } catch (IllegalInputException e) {
+ log.log(Level.FINE, () -> "Rejected query '" + query.toString() + "' on cause of: " + Exceptions.toMessageString(e));
return new Result(query, ErrorMessage.createIllegalQuery(e.getMessage()));
}
return execution.search(query);
@@ -92,8 +92,9 @@ public class InputCheckingSearcher extends Searcher {
repeatedCount++;
if (repeatedCount >= MAX_REPEATED_CONSECUTIVE_TERMS_IN_PHRASE) {
repeatedConsecutiveTermsInPhraseRejections.add();
- throw new IllegalArgumentException("More than " + MAX_REPEATED_CONSECUTIVE_TERMS_IN_PHRASE +
- " ocurrences of term '" + current + "' in a row detected in phrase : " + phrase.toString());
+ throw new IllegalInputException("More than " + MAX_REPEATED_CONSECUTIVE_TERMS_IN_PHRASE +
+ " occurrences of term '" + current +
+ "' in a row detected in phrase : " + phrase.toString());
}
} else {
repeatedCount = 0;
@@ -125,8 +126,8 @@ public class InputCheckingSearcher extends Searcher {
if (count != null) {
if (count.get() >= MAX_REPEATED_TERMS_IN_PHRASE) {
repeatedTermsInPhraseRejections.add();
- throw new IllegalArgumentException("Phrase contains more than " + MAX_REPEATED_TERMS_IN_PHRASE +
- " occurrences of term '" + current + "' in phrase : " + phrase.toString());
+ throw new IllegalInputException("Phrase contains more than " + MAX_REPEATED_TERMS_IN_PHRASE +
+ " occurrences of term '" + current + "' in phrase : " + phrase.toString());
}
count.inc();
} else {
@@ -169,8 +170,8 @@ public class InputCheckingSearcher extends Searcher {
return;
}
utfRejections.add();
- throw new IllegalArgumentException("The user input has been determined to be double encoded UTF-8."
- + " Please investigate whether this is a false positive.");
+ throw new IllegalInputException("The user input has been determined to be double encoded UTF-8."
+ + " Please investigate whether this is a false positive.");
}
private int countSingleCharacterUserTerms(Item queryItem) {
diff --git a/container-search/src/main/java/com/yahoo/search/statistics/PeakQpsSearcher.java b/container-search/src/main/java/com/yahoo/search/statistics/PeakQpsSearcher.java
index 108e46fb68e..6d4fcdaf8fb 100644
--- a/container-search/src/main/java/com/yahoo/search/statistics/PeakQpsSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/statistics/PeakQpsSearcher.java
@@ -137,8 +137,8 @@ public class PeakQpsSearcher extends Searcher {
useMetaHit = false;
propertyName = null;
} else {
- throw new IllegalArgumentException("Config definition out of sync with implementation." +
- " No way to create output for method " + method + ".");
+ throw new IllegalStateException("Config definition out of sync with implementation." +
+ " No way to create output for method " + method + ".");
}
}
diff --git a/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java b/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java
index 8b2438e3ec2..b863440ea5b 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/MinimalQueryInserter.java
@@ -5,6 +5,7 @@ import com.google.common.annotations.Beta;
import com.google.inject.Inject;
import com.yahoo.language.Linguistics;
import com.yahoo.language.simple.SimpleLinguistics;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
@@ -28,6 +29,7 @@ import java.util.logging.Logger;
*
* @author Steinar Knutsen
*/
+// TODO: The query model should do this
@Beta
@Provides(MinimalQueryInserter.EXTERNAL_YQL)
@Before(PhaseNames.TRANSFORMED_QUERY)
@@ -40,19 +42,22 @@ public class MinimalQueryInserter extends Searcher {
private static final CompoundName MAX_HITS = new CompoundName("maxHits");
private static final CompoundName MAX_OFFSET = new CompoundName("maxOffset");
- private static Logger log = Logger.getLogger(MinimalQueryInserter.class.getName());
+ private static final Logger log = Logger.getLogger(MinimalQueryInserter.class.getName());
@Inject
public MinimalQueryInserter(Linguistics linguistics) {
// Warmup is needed to avoid a large 400ms init cost during first execution of yql code.
warmup(linguistics);
}
+
public MinimalQueryInserter() {
this(new SimpleLinguistics());
}
+
static boolean warmup() {
return warmup(new SimpleLinguistics());
}
+
private static boolean warmup(Linguistics linguistics) {
Query query = new Query("search/?yql=select%20*%20from%20sources%20where%20title%20contains%20'xyz';");
Result result = insertQuery(query, new ParserEnvironment().setLinguistics(linguistics));
@@ -67,6 +72,18 @@ public class MinimalQueryInserter extends Searcher {
return true;
}
+ @Override
+ public Result search(Query query, Execution execution) {
+ try {
+ if (query.properties().get(YQL) == null) return execution.search(query);
+ Result result = insertQuery(query, ParserEnvironment.fromExecutionContext(execution.context()));
+ return (result == null) ? execution.search(query) : result;
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalInputException("Illegal YQL query", e);
+ }
+ }
+
private static Result insertQuery(Query query, ParserEnvironment env) {
YqlParser parser = (YqlParser) ParserFactory.newInstance(Query.Type.YQL, env);
parser.setQueryParser(false);
@@ -116,12 +133,4 @@ public class MinimalQueryInserter extends Searcher {
return null;
}
- @Override
- public Result search(Query query, Execution execution) {
- if (query.properties().get(YQL) == null) return execution.search(query);
-
- Result result = insertQuery(query, ParserEnvironment.fromExecutionContext(execution.context()));
- return (result == null) ? execution.search(query) : result;
- }
-
}
diff --git a/container-search/src/main/java/com/yahoo/search/yql/OperatorNode.java b/container-search/src/main/java/com/yahoo/search/yql/OperatorNode.java
index e3ef4b5d4df..f529de32fe9 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/OperatorNode.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/OperatorNode.java
@@ -162,7 +162,7 @@ final class OperatorNode<T extends Operator> {
}
// we are aware only of types used in our logical operator trees -- OperatorNode, List, and constant values
- private static final Function<Object, Object> COPY = new Function<Object, Object>() {
+ private static final Function<Object, Object> COPY = new Function<>() {
@Override
public Object apply(Object input) {
if (input instanceof List) {
diff --git a/container-search/src/main/java/com/yahoo/search/yql/ProgramParser.java b/container-search/src/main/java/com/yahoo/search/yql/ProgramParser.java
index a270d935a97..234558f5fd2 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/ProgramParser.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/ProgramParser.java
@@ -139,7 +139,7 @@ final class ProgramParser {
int charPositionInLine,
@NotNull String msg,
@Nullable RecognitionException e) {
- throw new ProgramCompileException(new Location(programName, line, charPositionInLine), msg);
+ throw new ProgramCompileException(new Location(programName, line, charPositionInLine), "%s", msg);
}
});
@@ -156,7 +156,7 @@ final class ProgramParser {
int charPositionInLine,
@NotNull String msg,
@Nullable RecognitionException e) {
- throw new ProgramCompileException(new Location(programName, line, charPositionInLine), msg);
+ throw new ProgramCompileException(new Location(programName, line, charPositionInLine), "%s", msg);
}
});
@@ -622,19 +622,19 @@ final class ProgramParser {
}
private OperatorNode<SequenceOperator> convertMerge(List<Merge_componentContext> mergeComponentList, Scope scope) {
- Preconditions.checkArgument(mergeComponentList != null);
- List<OperatorNode<SequenceOperator>> sources = Lists.newArrayListWithExpectedSize(mergeComponentList.size());
- for (Merge_componentContext mergeComponent:mergeComponentList) {
- Select_statementContext selectContext = mergeComponent.select_statement();
- Source_statementContext sourceContext = mergeComponent.source_statement();
- if (selectContext != null) {
- sources.add(convertQuery(selectContext, scope.getRoot()));
- } else {
- sources.add(convertQuery(sourceContext, scope.getRoot()));
- }
- }
- return OperatorNode.create(SequenceOperator.MERGE, sources);
- }
+ Preconditions.checkArgument(mergeComponentList != null);
+ List<OperatorNode<SequenceOperator>> sources = Lists.newArrayListWithExpectedSize(mergeComponentList.size());
+ for (Merge_componentContext mergeComponent:mergeComponentList) {
+ Select_statementContext selectContext = mergeComponent.select_statement();
+ Source_statementContext sourceContext = mergeComponent.source_statement();
+ if (selectContext != null) {
+ sources.add(convertQuery(selectContext, scope.getRoot()));
+ } else {
+ sources.add(convertQuery(sourceContext, scope.getRoot()));
+ }
+ }
+ return OperatorNode.create(SequenceOperator.MERGE, sources);
+ }
private OperatorNode<SequenceOperator> convertQuery(ParseTree node, Scope scope) {
if (node instanceof Select_statementContext
@@ -642,7 +642,7 @@ final class ProgramParser {
|| node instanceof Update_statementContext
|| node instanceof Delete_statementContext) {
return convertSelectOrInsertOrUpdateOrDelete(node, scope.getRoot());
- } else if (node instanceof Source_statementContext) { //for pipe
+ } else if (node instanceof Source_statementContext) { // for pipe
Source_statementContext sourceStatementContext = (Source_statementContext)node;
return convertPipe(sourceStatementContext.query_statement(), sourceStatementContext.pipeline_step(), scope);
} else if (node instanceof Merge_statementContext) {
diff --git a/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java b/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
index 22328fb026e..a38e48fd89d 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/VespaSerializer.java
@@ -142,7 +142,7 @@ public class VespaSerializer {
escape(((WordItem) current).getIndexedString(), destination).append('"');
} else {
throw new IllegalArgumentException("Serializing of " + current.getClass().getSimpleName()
- + " in segment AND expressions not implemented, please report this as a bug.");
+ + " in segment AND expressions not implemented, please report this as a bug.");
}
}
}
@@ -643,7 +643,7 @@ public class VespaSerializer {
WordAlternativesSerializer.serialize(destination, (WordAlternativesItem) current, false);
} else {
throw new IllegalArgumentException("Serializing of " + current.getClass().getSimpleName() +
- " in phrases not implemented, please report this as a bug.");
+ " in phrases not implemented, please report this as a bug.");
}
}
destination.append(')');
@@ -1158,7 +1158,7 @@ public class VespaSerializer {
Serializer doIt = dispatch.get(item.getClass());
if (doIt == null) {
- throw new IllegalArgumentException(item.getClass() + " not supported for YQL+ marshalling.");
+ throw new IllegalArgumentException(item.getClass() + " not supported for YQL marshalling.");
}
if (state.peekFirst() != null && state.peekFirst().subItems > 0) {
diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
index 31a22fd3b58..3875018609e 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
@@ -67,6 +67,7 @@ import com.yahoo.prelude.query.WeakAndItem;
import com.yahoo.prelude.query.WeightedSetItem;
import com.yahoo.prelude.query.WordAlternativesItem;
import com.yahoo.prelude.query.WordItem;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.Query;
import com.yahoo.search.grouping.Continuation;
import com.yahoo.search.grouping.request.GroupingOperation;
@@ -318,10 +319,10 @@ public class YqlParser implements Parser {
private void connectItems() {
for (ConnectedItem entry : connectedItems) {
TaggableItem to = identifiedItems.get(entry.toId);
- Preconditions.checkNotNull(to,
- "Item '%s' was specified to connect to item with ID %s, which does not "
- + "exist in the query.", entry.fromItem,
- entry.toId);
+ if (to == null)
+ throw new IllegalArgumentException("Item '" + entry.fromItem +
+ "' was specified to connect to item with ID " + entry.toId +
+ ", which does not exist in the query.");
entry.fromItem.setConnectivity((Item) to, entry.weight);
}
}
@@ -782,7 +783,7 @@ public class YqlParser implements Parser {
try {
ast = new ProgramParser().parse("query", currentlyParsing.getQuery());
} catch (Exception e) {
- throw new IllegalArgumentException(e);
+ throw new IllegalInputException(e);
}
assertHasOperator(ast, StatementOperator.PROGRAM);
Preconditions.checkArgument(ast.getArguments().length == 1,
diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
index 8bd7bdac8a5..d06c4cd6f01 100644
--- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsStreamingSearcher.java
@@ -163,7 +163,7 @@ public class VdsStreamingSearcher extends VespaBackEndSearcher {
query.toString(), elapsedMillis / 1000.0)));
}
return new Result(query, ErrorMessage.createTimeout(e.getMessage()));
- } catch (InterruptedException|IllegalArgumentException e) {
+ } catch (InterruptedException | IllegalArgumentException e) {
return new Result(query, ErrorMessage.createBackendCommunicationError(e.getMessage()));
}
diff --git a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
index 2b0d8adc8ef..b05ddfa3bb2 100644
--- a/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
+++ b/container-search/src/main/java/com/yahoo/vespa/streamingvisitors/VdsVisitor.java
@@ -346,9 +346,9 @@ class VdsVisitor extends VisitorDataHandler implements Visitor {
log.log(Level.FINE, "VdsVisitor completed successfully for " + query + " with selection " + params.getDocumentSelection());
}
} else {
- throw new IllegalArgumentException("Query failed: " // TODO: Is it necessary to use a runtime exception?
- + params.getControlHandler().getResult().code + ": "
- + params.getControlHandler().getResult().message);
+ throw new IllegalArgumentException("Query failed: " +
+ params.getControlHandler().getResult().code + ": " +
+ params.getControlHandler().getResult().message);
}
}
@@ -425,7 +425,8 @@ class VdsVisitor extends VisitorDataHandler implements Visitor {
BufferSerializer buf = new BufferSerializer( new GrowableByteBuffer(ByteBuffer.wrap(value)) );
newGrouping.deserialize(buf);
if (buf.getBuf().hasRemaining()) {
- throw new IllegalArgumentException("Failed deserializing grouping. There are still data left. Position = " + buf.position() + ", limit = " + buf.getBuf().limit());
+ throw new IllegalArgumentException("Failed deserializing grouping. There is still data left. " +
+ "Position = " + buf.position() + ", limit = " + buf.getBuf().limit());
}
synchronized (groupingMap) {
diff --git a/container-search/src/test/java/com/yahoo/prelude/query/ItemsCommonStuffTestCase.java b/container-search/src/test/java/com/yahoo/prelude/query/ItemsCommonStuffTestCase.java
index a080ae653e5..204ccff7fb3 100644
--- a/container-search/src/test/java/com/yahoo/prelude/query/ItemsCommonStuffTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/query/ItemsCommonStuffTestCase.java
@@ -42,7 +42,7 @@ public class ItemsCommonStuffTestCase {
a.addItem(as);
try {
as.addItem(a);
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
caught = true;
}
assertTrue(caught);
@@ -51,7 +51,7 @@ public class ItemsCommonStuffTestCase {
as.addItem(a);
try {
a.addItem(as);
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
caught = true;
}
assertTrue(caught);
@@ -235,21 +235,21 @@ public class ItemsCommonStuffTestCase {
boolean caught = false;
try {
as.removeItem(firstItem);
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
caught = true;
}
assertTrue(caught);
caught = false;
try {
as.addItem(new WordItem("puppy"));
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
caught= true;
}
assertTrue(caught);
caught = false;
try {
as.addItem(1, new WordItem("kvalp"));
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
caught = true;
}
assertTrue(caught);
diff --git a/container-search/src/test/java/com/yahoo/prelude/test/QueryTestCase.java b/container-search/src/test/java/com/yahoo/prelude/test/QueryTestCase.java
index 4b2ced1b771..a04834b261c 100644
--- a/container-search/src/test/java/com/yahoo/prelude/test/QueryTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/test/QueryTestCase.java
@@ -8,25 +8,21 @@ import com.yahoo.prelude.Index;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.IndexModel;
import com.yahoo.prelude.SearchDefinition;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.prelude.query.WordItem;
import com.yahoo.search.Query;
import com.yahoo.search.query.Sorting;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.yolean.Exceptions;
import org.hamcrest.Matcher;
-import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
-import java.util.Collections;
import java.util.List;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.junit.Assert.*;
-import static org.junit.Assume.assumeTrue;
/**
* Tests for query class
@@ -376,7 +372,7 @@ public class QueryTestCase {
try {
newQuery(queryString);
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertThat(Exceptions.toMessageString(e), expectedErrorMessage);
}
diff --git a/container-search/src/test/java/com/yahoo/search/grouping/UniqueGroupingSearcherTestCase.java b/container-search/src/test/java/com/yahoo/search/grouping/UniqueGroupingSearcherTestCase.java
index 8ff03b35b60..86ab96a2197 100644
--- a/container-search/src/test/java/com/yahoo/search/grouping/UniqueGroupingSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/grouping/UniqueGroupingSearcherTestCase.java
@@ -2,7 +2,6 @@
package com.yahoo.search.grouping;
import com.yahoo.component.chain.Chain;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
@@ -41,18 +40,19 @@ public class UniqueGroupingSearcherTestCase {
new MockResultProvider(0, false));
assertEquals(0, result.hits().size());
}
+
@Test
public void testIllegalSortingSpec() {
try {
search("?query=foo&unique=fingerprint&sorting=-1",
new MockResultProvider(0, true).addGroupList(new GroupList("fingerprint")));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertThat(
Exceptions.toMessageString(e),
containsString(
- "Invalid request parameter: Could not set 'ranking.sorting' to '-1': " +
+ "Could not set 'ranking.sorting' to '-1': " +
"Illegal attribute name '1' for sorting. Requires '[\\[]*[a-zA-Z_][\\.a-zA-Z0-9_-]*[\\]]*'"));
}
}
diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java
index 272092b6fc0..3cca053d0e5 100644
--- a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java
@@ -169,7 +169,7 @@ public class JSONSearchHandlerTestCase {
String response = responseHandler.readAll();
assertThat(responseHandler.getStatus(), is(400));
assertThat(response, containsString("offset"));
- assertThat(response, containsString("\"code\":" + com.yahoo.container.protect.Error.INVALID_QUERY_PARAMETER.code));
+ assertThat(response, containsString("\"code\":" + com.yahoo.container.protect.Error.ILLEGAL_QUERY.code));
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java
index c96af2ed4d1..7d03e065fa9 100644
--- a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java
@@ -201,7 +201,7 @@ public class SearchHandlerTestCase {
String response = responseHandler.readAll();
assertThat(responseHandler.getStatus(), is(400));
assertThat(response, containsString("offset"));
- assertThat(response, containsString("\"code\":" + com.yahoo.container.protect.Error.INVALID_QUERY_PARAMETER.code));
+ assertThat(response, containsString("\"code\":" + com.yahoo.container.protect.Error.ILLEGAL_QUERY.code));
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java b/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java
index 462e5284972..3b6b3c7d7c6 100644
--- a/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/query/MatchingTestCase.java
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import org.junit.Test;
@@ -12,9 +11,10 @@ import static org.junit.Assert.assertEquals;
* @author baldersheim
*/
public class MatchingTestCase {
+
@Test
public void testDefaultsInQuery() {
- Query query=new Query("?query=test");
+ Query query = new Query("?query=test");
assertNull(query.getRanking().getMatching().getTermwiseLimit());
assertNull(query.getRanking().getMatching().getNumThreadsPerSearch());
assertNull(query.getRanking().getMatching().getNumSearchPartitions());
@@ -24,7 +24,7 @@ public class MatchingTestCase {
@Test
public void testQueryOverride() {
- Query query=new Query("?query=test&ranking.matching.termwiselimit=0.7&ranking.matching.numthreadspersearch=17&ranking.matching.numsearchpartitions=13&ranking.matching.minhitsperthread=3");
+ Query query = new Query("?query=test&ranking.matching.termwiselimit=0.7&ranking.matching.numthreadspersearch=17&ranking.matching.numsearchpartitions=13&ranking.matching.minhitsperthread=3");
assertEquals(Double.valueOf(0.7), query.getRanking().getMatching().getTermwiseLimit());
assertEquals(Integer.valueOf(17), query.getRanking().getMatching().getNumThreadsPerSearch());
assertEquals(Integer.valueOf(13), query.getRanking().getMatching().getNumSearchPartitions());
@@ -40,16 +40,17 @@ public class MatchingTestCase {
private void verifyException(String key, String value) {
try {
new Query("?query=test&ranking.matching."+key+"="+value);
- assertFalse(true);
- } catch (QueryException e) {
- assertEquals("Invalid request parameter", e.getMessage());
- assertEquals("Could not set 'ranking.matching." + key + "' to '" + value +"'", e.getCause().getMessage());
- assertEquals(key + " must be in the range [0.0, 1.0]. It is " + value, e.getCause().getCause().getMessage());
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Could not set 'ranking.matching." + key + "' to '" + value +"'", e.getMessage());
+ assertEquals(key + " must be in the range [0.0, 1.0]. It is " + value, e.getCause().getMessage());
}
}
+
@Test
public void testLimits() {
verifyException("termwiselimit", "-0.1");
verifyException("termwiselimit", "1.1");
}
+
}
diff --git a/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java b/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java
index dff6d4c26c3..a15038ff7e2 100644
--- a/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/query/SoftTimeoutTestCase.java
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -10,9 +9,10 @@ import static org.junit.Assert.*;
* @author baldersheim
*/
public class SoftTimeoutTestCase {
+
@Test
public void testDefaultsInQuery() {
- Query query=new Query("?query=test");
+ Query query = new Query("?query=test");
assertTrue(query.getRanking().getSoftTimeout().getEnable());
assertNull(query.getRanking().getSoftTimeout().getFactor());
assertNull(query.getRanking().getSoftTimeout().getTailcost());
@@ -20,7 +20,7 @@ public class SoftTimeoutTestCase {
@Test
public void testQueryOverride() {
- Query query=new Query("?query=test&ranking.softtimeout.factor=0.7&ranking.softtimeout.tailcost=0.3");
+ Query query = new Query("?query=test&ranking.softtimeout.factor=0.7&ranking.softtimeout.tailcost=0.3");
assertTrue(query.getRanking().getSoftTimeout().getEnable());
assertEquals(Double.valueOf(0.7), query.getRanking().getSoftTimeout().getFactor());
assertEquals(Double.valueOf(0.3), query.getRanking().getSoftTimeout().getTailcost());
@@ -49,13 +49,13 @@ public class SoftTimeoutTestCase {
private void verifyException(String key, String value) {
try {
new Query("?query=test&ranking.softtimeout."+key+"="+value);
- assertFalse(true);
- } catch (QueryException e) {
- assertEquals("Invalid request parameter", e.getMessage());
- assertEquals("Could not set 'ranking.softtimeout." + key + "' to '" + value +"'", e.getCause().getMessage());
- assertEquals(key + " must be in the range [0.0, 1.0], got " + value, e.getCause().getCause().getMessage());
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Could not set 'ranking.softtimeout." + key + "' to '" + value +"'", e.getMessage());
+ assertEquals(key + " must be in the range [0.0, 1.0], got " + value, e.getCause().getMessage());
}
}
+
@Test
public void testLimits() {
verifyException("factor", "-0.1");
@@ -63,4 +63,5 @@ public class SoftTimeoutTestCase {
verifyException("tailcost", "-0.1");
verifyException("tailcost", "1.1");
}
+
}
diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/NativePropertiesTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/NativePropertiesTestCase.java
index 224b0c82339..2ced2ba9323 100644
--- a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/NativePropertiesTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/NativePropertiesTestCase.java
@@ -3,7 +3,6 @@ package com.yahoo.search.query.profile.types.test;
import com.yahoo.jdisc.http.HttpRequest.Method;
import com.yahoo.container.jdisc.HttpRequest;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import com.yahoo.search.query.profile.QueryProfile;
import com.yahoo.search.query.profile.types.QueryProfileType;
@@ -23,22 +22,22 @@ public class NativePropertiesTestCase {
@Test
public void testNativeInStrict() {
- QueryProfileType strictType=new QueryProfileType("strict");
+ QueryProfileType strictType = new QueryProfileType("strict");
strictType.setStrict(true);
- QueryProfile strict=new QueryProfile("profile");
+ QueryProfile strict = new QueryProfile("profile");
strict.setType(strictType);
try {
new Query(HttpRequest.createTestRequest("?hits=10&tracelevel=5", Method.GET), strict.compile(null));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
}
try {
new Query(HttpRequest.createTestRequest("?notnative=5", Method.GET), strict.compile(null));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertThat(
Exceptions.toMessageString(e),
diff --git a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/QueryProfileTypeTestCase.java b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/QueryProfileTypeTestCase.java
index ecebbead866..a0bf0972281 100644
--- a/container-search/src/test/java/com/yahoo/search/query/profile/types/test/QueryProfileTypeTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/query/profile/types/test/QueryProfileTypeTestCase.java
@@ -2,9 +2,7 @@
package com.yahoo.search.query.profile.types.test;
import com.yahoo.component.ComponentId;
-import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.container.jdisc.HttpRequest;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.tensor.Tensor;
import com.yahoo.yolean.Exceptions;
import com.yahoo.search.Query;
@@ -434,7 +432,7 @@ public class QueryProfileTypeTestCase {
com.yahoo.jdisc.http.HttpRequest.Method.GET),
profile.compile(null));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertThat(Exceptions.toMessageString(e),
containsString("Could not set 'myUserQueryProfile.nondeclared' to 'someValue': 'nondeclared' is not declared in query profile type 'userStrict', and the type is strict"));
@@ -549,7 +547,7 @@ public class QueryProfileTypeTestCase {
com.yahoo.jdisc.http.HttpRequest.Method.GET),
cRegistry.getComponent("topMap"));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertThat(Exceptions.toMessageString(e),
containsString("Could not set 'subMap.typeProfile.someValue' to 'value': 'someValue' is not declared in query profile type 'testtypeStrict', and the type is strict"));
diff --git a/container-search/src/test/java/com/yahoo/search/querytransform/test/SortingDegraderTestCase.java b/container-search/src/test/java/com/yahoo/search/querytransform/test/SortingDegraderTestCase.java
index 5a14cff1818..ab65e258477 100644
--- a/container-search/src/test/java/com/yahoo/search/querytransform/test/SortingDegraderTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/querytransform/test/SortingDegraderTestCase.java
@@ -6,7 +6,6 @@ import com.yahoo.prelude.Index;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.IndexModel;
import com.yahoo.prelude.SearchDefinition;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
@@ -16,8 +15,6 @@ import com.yahoo.search.querytransform.SortingDegrader;
import com.yahoo.search.searchchain.Execution;
import org.junit.Test;
-import java.util.Collections;
-
import static org.junit.Assert.*;
/**
@@ -67,12 +64,10 @@ public class SortingDegraderTestCase {
try {
Query query = new Query("?ranking.sorting=-a1%20-a2&ranking.matchPhase.maxFilterCoverage=37");
assertTrue(false);
- } catch (QueryException qe) {
- assertEquals("Invalid request parameter", qe.getMessage());
- Throwable setE = qe.getCause();
- assertTrue(setE instanceof IllegalArgumentException);
- assertEquals("Could not set 'ranking.matchPhase.maxFilterCoverage' to '37'", setE.getMessage());
- Throwable rootE = setE.getCause();
+ } catch (IllegalArgumentException qe) {
+ assertTrue(qe instanceof IllegalArgumentException);
+ assertEquals("Could not set 'ranking.matchPhase.maxFilterCoverage' to '37'", qe.getMessage());
+ Throwable rootE = qe.getCause();
assertTrue(rootE instanceof IllegalArgumentException);
assertEquals("maxFilterCoverage must be in the range [0.0, 1.0]. It is 37.0", rootE.getMessage());
}
diff --git a/container-search/src/test/java/com/yahoo/search/searchers/test/InputCheckingSearcherTestCase.java b/container-search/src/test/java/com/yahoo/search/searchers/test/InputCheckingSearcherTestCase.java
index aa507d38be5..9bf5b654a6d 100644
--- a/container-search/src/test/java/com/yahoo/search/searchers/test/InputCheckingSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/searchers/test/InputCheckingSearcherTestCase.java
@@ -85,7 +85,7 @@ public class InputCheckingSearcherTestCase {
assertNull(r.hits().getErrorHit());
r = execution.search(new Query("/search/?query=%22a.b.0.0.0.0.0.0.c%22"));
assertNotNull(r.hits().getErrorHit());
- assertEquals("More than 5 ocurrences of term '0' in a row detected in phrase : \"a b 0 0 0 0 0 0 c\"",
+ assertEquals("More than 5 occurrences of term '0' in a row detected in phrase : \"a b 0 0 0 0 0 0 c\"",
r.hits().getErrorHit().errorIterator().next().getDetailedMessage());
r = execution.search(new Query("/search/?query=a.b.0.0.0.1.0.0.0.c"));
assertNull(r.hits().getErrorHit());
@@ -97,7 +97,7 @@ public class InputCheckingSearcherTestCase {
assertNull(r.hits().getErrorHit());
r = execution.search(new Query("/search/?query=%22a.b.0.0.0.0.0.0.c%22"));
assertNotNull(r.hits().getErrorHit());
- assertEquals("More than 5 ocurrences of term '0' in a row detected in phrase : \"a b 0 0 0 0 0 0 c\"",
+ assertEquals("More than 5 occurrences of term '0' in a row detected in phrase : \"a b 0 0 0 0 0 0 c\"",
r.hits().getErrorHit().errorIterator().next().getDetailedMessage());
r = execution.search(new Query("/search/?query=%22a.b.0.0.0.1.0.0.0.c%22"));
assertNull(r.hits().getErrorHit());
diff --git a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
index 3a67245e912..a42a2ee55aa 100644
--- a/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/test/QueryTestCase.java
@@ -23,7 +23,6 @@ import com.yahoo.prelude.query.IndexedItem;
import com.yahoo.prelude.query.IntItem;
import com.yahoo.prelude.query.Item;
import com.yahoo.prelude.query.OrItem;
-import com.yahoo.prelude.query.QueryException;
import com.yahoo.prelude.query.RankItem;
import com.yahoo.prelude.query.WordItem;
import com.yahoo.processing.request.CompoundName;
@@ -47,7 +46,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -289,7 +287,7 @@ public class QueryTestCase {
try {
new Query(httpEncode("/search?timeout=nalle"));
fail("Above statement should throw");
- } catch (QueryException e) {
+ } catch (IllegalArgumentException e) {
// As expected.
assertTrue(Exceptions.toMessageString(e).contains("Could not set 'timeout' to 'nalle': Error parsing 'nalle': Invalid number 'nalle'"));
}
@@ -865,7 +863,7 @@ public class QueryTestCase {
root.addItem(child);
fail("Expected exception");
}
- catch (QueryException e) {
+ catch (IllegalArgumentException e) {
assertEquals("Cannot add OR (AND ) to (AND ) as it would create a cycle", e.getMessage());
}
@@ -875,7 +873,7 @@ public class QueryTestCase {
child.addItem(root);
fail("Expected exception");
}
- catch (QueryException e) {
+ catch (IllegalArgumentException e) {
assertEquals("Cannot add (AND (OR )) to (OR ) as it would create a cycle", e.getMessage());
}
}
diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
index 1b8324c9de8..f5e22e30f45 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
@@ -449,8 +449,8 @@ public class YqlParserTestCase {
"title contains ([{\"id\": 1, \"connectivity\": {\"id\": 4, \"weight\": 7.0}}]\"madonna\") " +
"and title contains ([{\"id\": 2}]\"saint\") " +
"and title contains ([{\"id\": 3}]\"angel\");",
- new NullPointerException("Item 'title:madonna' was specified to connect to item with ID 4, " +
- "which does not exist in the query."));
+ new IllegalArgumentException("Item 'title:madonna' was specified to connect to item with ID 4, " +
+ "which does not exist in the query."));
}
@Test
diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
index f297fd69f24..c802eb18c0f 100644
--- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
+++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java
@@ -14,6 +14,7 @@ import com.yahoo.prelude.query.SuffixItem;
import com.yahoo.prelude.query.WeakAndItem;
import com.yahoo.prelude.query.WordAlternativesItem;
import com.yahoo.prelude.query.WordItem;
+import com.yahoo.processing.IllegalInputException;
import com.yahoo.search.Query;
import com.yahoo.search.grouping.GroupingRequest;
import com.yahoo.search.grouping.request.AllOperation;
@@ -423,7 +424,7 @@ public class SelectTestCase {
assertParseFail("{ \"and\": [ {\"contains\" : { \"children\" : [\"title\", \"madonna\"], \"attributes\" : {\"id\": 1, \"connectivity\": {\"id\": 4, \"weight\": 7.0}} } }, " +
"{ \"contains\" : { \"children\" : [\"title\", \"saint\"], \"attributes\" : {\"id\": 2} } }, " +
"{ \"contains\" : { \"children\" : [\"title\", \"angel\"], \"attributes\" : {\"id\": 3} } } ] }",
- new NullPointerException("Item 'title:madonna' was specified to connect to item with ID 4, " +
+ new IllegalArgumentException("Item 'title:madonna' was specified to connect to item with ID 4, " +
"which does not exist in the query."));
}
@@ -618,7 +619,7 @@ public class SelectTestCase {
parseWhere("{ \"range\" : { \"children\":[ \"foo\", { \">=\" : 0, \"<=\" : 1 }], \"attributes\" : {\"hitLimit\": 38, \"ascending\": true, \"descending\": false} } }");
} catch (IllegalArgumentException e) {
assertTrue("Expected information about abuse of settings.",
- e.getMessage().contains("both ascending and descending ordering set"));
+ e.getCause().getMessage().contains("both ascending and descending ordering set"));
gotExceptionFromParse = true;
}
assertTrue(gotExceptionFromParse);
@@ -775,12 +776,14 @@ public class SelectTestCase {
private void assertParseFail(String where, Throwable expectedException) {
try {
parseWhere(where).toString();
- } catch (Throwable t) {
- assertEquals(expectedException.getClass(), t.getClass());
- assertEquals(expectedException.getMessage(), t.getMessage());
- return;
+ fail("Parse succeeded: " + where);
+ } catch (Throwable outer) {
+ assertEquals(IllegalInputException.class, outer.getClass());
+ assertEquals("Illegal JSON query", outer.getMessage());
+ Throwable cause = outer.getCause();
+ assertEquals(expectedException.getClass(), cause.getClass());
+ assertEquals(expectedException.getMessage(), cause.getMessage());
}
- fail("Parse succeeded: " + where);
}
private void assertRootClass(String where, Class<? extends Item> expectedRootClass) {
diff --git a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsVisitorTestCase.java b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsVisitorTestCase.java
index 7841b6f715c..4bfbd91eb89 100644
--- a/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsVisitorTestCase.java
+++ b/container-search/src/test/java/com/yahoo/vespa/streamingvisitors/VdsVisitorTestCase.java
@@ -130,7 +130,7 @@ public class VdsVisitorTestCase {
traceLevel = 100;
summary = "fancysummary";
profile = "fancyprofile";
- location = "(1,10000,2000,0,1,0)";
+ location = "(2,10000,2000,0,0,1,0)";
sortSpec = "+surname -yearofbirth";
rankProperties = "rankfeature.something=2";
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/DeploymentStatistics.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/DeploymentStatistics.java
index 99cf7542d53..df018d64748 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/DeploymentStatistics.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/DeploymentStatistics.java
@@ -84,13 +84,14 @@ public class DeploymentStatistics {
for (Deployment deployment : instance.productionDeployments().values())
allVersions.add(deployment.version());
- JobList failing = status.jobs().failing();
+ JobList failing = status.jobs().failing()
+ .not().withStatus(RunStatus.outOfCapacity)
+ .not().withStatus(RunStatus.aborted);
- // Add all unsuccessful runs for failing jobs as any run may have resulted in an incomplete deployment
+ // Add all unsuccessful runs for failing production jobs as any run may have resulted in an incomplete deployment
// where a subset of nodes have upgraded.
failing.not().failingApplicationChange()
- .not().withStatus(RunStatus.outOfCapacity)
- .not().withStatus(RunStatus.aborted)
+ .production()
.mapToList(JobStatus::runs)
.forEach(runs -> runs.descendingMap().values().stream()
.dropWhile(run -> ! run.hasEnded())
@@ -101,9 +102,17 @@ public class DeploymentStatistics {
failingUpgrade.get(run.versions().targetPlatform()).add(run);
}));
+ // Add only the last failing run for test jobs.
+ failing.not().failingApplicationChange()
+ .not().production()
+ .lastCompleted().asList()
+ .forEach(run -> {
+ failingUpgrade.putIfAbsent(run.versions().targetPlatform(), new ArrayList<>());
+ failingUpgrade.get(run.versions().targetPlatform()).add(run);
+ });
+
+ // Add only the last failing for instances failing only an application change, i.e., no upgrade.
failing.failingApplicationChange()
- .concat(failing.withStatus(RunStatus.outOfCapacity))
- .concat(failing.withStatus(RunStatus.aborted))
.lastCompleted().asList()
.forEach(run -> {
otherFailing.putIfAbsent(run.versions().targetPlatform(), new ArrayList<>());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
index 157941bd092..dcb7a6dd42b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
@@ -162,6 +162,10 @@ public class DeploymentIssueReporterTest {
reporter.maintain();
assertTrue("We get a platform issue when confidence is broken", issues.platformIssue());
assertFalse("No deployment issue is filed for app2, which has a version upgrade failure.", issues.isOpenFor(app2.application().id()));
+
+ app2.runJob(systemTest);
+ tester.controllerTester().upgradeSystem(version);
+ assertEquals(VespaVersion.Confidence.low, tester.controller().versionStatus().systemVersion().get().confidence());
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
index 44e172d9f93..3ea9d038d99 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
@@ -385,6 +385,86 @@ public class VersionStatusTest {
}
@Test
+ public void testConfidenceWithLingeringVersions() {
+ DeploymentTester tester = new DeploymentTester().atMondayMorning();
+ Version version0 = new Version("6.2");
+ tester.controllerTester().upgradeSystem(version0);
+ tester.upgrader().maintain();
+ var appPackage = new ApplicationPackageBuilder().region("us-west-1").region("us-east-3").upgradePolicy("canary");
+
+ var canary0 = tester.newDeploymentContext("tenant1", "canary0", "default")
+ .submit(appPackage.build())
+ .deploy();
+
+ assertEquals("All applications running on this version: High",
+ Confidence.high, confidence(tester.controller(), version0));
+
+ // New version is released
+ Version version1 = new Version("6.3");
+ tester.controllerTester().upgradeSystem(version1);
+ tester.upgrader().maintain();
+ tester.triggerJobs();
+
+ // App upgrades to the new version and fails
+ canary0.failDeployment(systemTest);
+ canary0.abortJob(stagingTest);
+ tester.controllerTester().computeVersionStatus();
+ assertEquals("One canary failed: Broken",
+ Confidence.broken, confidence(tester.controller(), version1));
+
+ // New version is released
+ Version version2 = new Version("6.4");
+ tester.controllerTester().upgradeSystem(version2);
+ tester.upgrader().maintain();
+ assertEquals("Confidence remains unchanged for version1 until app overrides old tests: Broken",
+ Confidence.broken, confidence(tester.controller(), version1));
+ assertEquals("Confidence defaults to low for version with no applications",
+ Confidence.low, confidence(tester.controller(), version2));
+ assertEquals(version2, canary0.instance().change().platform().orElseThrow());
+
+ canary0.failDeployment(systemTest);
+ canary0.abortJob(stagingTest);
+ tester.controllerTester().computeVersionStatus();
+ assertFalse("Previous version should be forgotten, as canary only had test jobs run on it",
+ tester.controller().versionStatus().versions().stream().anyMatch(version -> version.versionNumber().equals(version1)));
+
+ // App succeeds with tests, but fails production deployment
+ canary0.runJob(systemTest)
+ .runJob(stagingTest)
+ .failDeployment(productionUsWest1);
+
+ assertEquals("One canary failed: Broken",
+ Confidence.broken, confidence(tester.controller(), version2));
+
+ // A new version is released, and the app again fails production deployment.
+ Version version3 = new Version("6.5");
+ tester.controllerTester().upgradeSystem(version3);
+ tester.upgrader().maintain();
+ assertEquals("Confidence remains unchanged for version2: Broken",
+ Confidence.broken, confidence(tester.controller(), version2));
+ assertEquals("Confidence defaults to low for version with no applications",
+ Confidence.low, confidence(tester.controller(), version3));
+ assertEquals(version3, canary0.instance().change().platform().orElseThrow());
+
+ canary0.runJob(systemTest)
+ .runJob(stagingTest)
+ .failDeployment(productionUsWest1);
+ tester.controllerTester().computeVersionStatus();
+ assertEquals("Confidence remains unchanged for version2: Broken",
+ Confidence.broken, confidence(tester.controller(), version2));
+ assertEquals("Canary broken, so confidence for version3: Broken",
+ Confidence.broken, confidence(tester.controller(), version3));
+
+ // App succeeds production deployment, clearing failure on version2
+ canary0.runJob(productionUsWest1);
+ tester.controllerTester().computeVersionStatus();
+ assertFalse("Previous version should be forgotten, as canary only had test jobs run on it",
+ tester.controller().versionStatus().versions().stream().anyMatch(version -> version.versionNumber().equals(version2)));
+ assertEquals("Canary OK, but not done upgrading, so confidence for version3: Low",
+ Confidence.low, confidence(tester.controller(), version3));
+ }
+
+ @Test
public void testConfidenceOverride() {
DeploymentTester tester = new DeploymentTester();
Version version0 = new Version("6.2");
diff --git a/default_build_settings.cmake b/default_build_settings.cmake
index 5ba7494d1e1..07a70c38d71 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}")
@@ -96,6 +96,11 @@ function(setup_vespa_default_build_settings_ubuntu_20_04)
set(DEFAULT_VESPA_LLVM_VERSION "10" PARENT_SCOPE)
endfunction()
+function(setup_vespa_default_build_settings_debian_10)
+ message("-- Setting up default build settings for debian 10")
+ set(DEFAULT_VESPA_LLVM_VERSION "7" PARENT_SCOPE)
+endfunction()
+
function(vespa_use_default_vespa_unprivileged)
if(NOT DEFINED VESPA_UNPRIVILEGED)
message("-- Setting VESPA_UNPRIVILEGED to yes")
@@ -185,6 +190,8 @@ function(vespa_use_default_build_settings)
setup_vespa_default_build_settings_ubuntu_19_10()
elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "ubuntu 20.04")
setup_vespa_default_build_settings_ubuntu_20_04()
+ elseif(VESPA_OS_DISTRO_COMBINED STREQUAL "debian 10")
+ setup_vespa_default_build_settings_debian_10()
else()
message(FATAL_ERROR "-- Unkonwn vespa build platform ${VESPA_OS_DISTRO_COMBINED}")
endif()
@@ -278,8 +285,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/functions.cmake b/functions.cmake
index 864fc010faa..95828430768 100644
--- a/functions.cmake
+++ b/functions.cmake
@@ -710,3 +710,23 @@ endfunction()
function(vespa_install_empty_tmp_dir TARGET)
install(DIRECTORY DESTINATION ${TARGET} DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_WRITE WORLD_EXECUTE SETGID)
endfunction()
+
+function(vespa_suppress_warnings_for_protobuf_sources)
+ cmake_parse_arguments(
+ ARG
+ ""
+ ""
+ "SOURCES"
+ ${ARGN}
+ )
+ # protoc-generated files emit compiler warnings that we normally treat as errors.
+ # Instead of rolling our own compiler plugin we'll pragmatically disable the noise.
+ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ if(Protobuf_VERSION VERSION_LESS "3.7.0")
+ set(VESPA_DISABLE_UNUSED_WARNING "-Wno-unused-parameter")
+ else()
+ unset(VESPA_DISABLE_UNUSED_WARNING)
+ endif()
+ set_source_files_properties(${ARG_SOURCES} PROPERTIES COMPILE_FLAGS "-Wno-array-bounds -Wno-suggest-override -Wno-inline ${VESPA_DISABLE_UNUSED_WARNING}")
+ endif()
+endfunction()
diff --git a/hosted-tenant-base/pom.xml b/hosted-tenant-base/pom.xml
index 40fc041204d..7afafb96280 100644
--- a/hosted-tenant-base/pom.xml
+++ b/hosted-tenant-base/pom.xml
@@ -34,7 +34,7 @@
<properties>
<vespaversion>${project.version}</vespaversion>
<target_jdk_version>11</target_jdk_version>
- <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
+ <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>
<junit.version>5.6.2</junit.version> <!-- NOTE: this must be in sync with junit version specified in 'tenant-cd-api' -->
<test.categories>!integration</test.categories>
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/test/TestTimer.java b/jdisc_core/src/main/java/com/yahoo/jdisc/test/TestTimer.java
index 4d274a33a1f..980e8e008b6 100644
--- a/jdisc_core/src/main/java/com/yahoo/jdisc/test/TestTimer.java
+++ b/jdisc_core/src/main/java/com/yahoo/jdisc/test/TestTimer.java
@@ -4,6 +4,8 @@ package com.yahoo.jdisc.test;
import com.yahoo.jdisc.Timer;
import java.time.Duration;
+import java.time.Instant;
+import java.util.Objects;
/**
* A {@link Timer} to be used in tests when the advancement of time needs to be controlled.
@@ -11,21 +13,34 @@ import java.time.Duration;
* @author hakonhall
*/
public class TestTimer implements Timer {
- private Duration durationSinceEpoch = Duration.ZERO;
+ private Instant instant;
+
+ public TestTimer() {
+ this(Instant.EPOCH);
+ }
+
+ public TestTimer(Instant instant) {
+ this.instant = Objects.requireNonNull(instant);
+ }
public void setMillis(long millisSinceEpoch) {
- durationSinceEpoch = Duration.ofMillis(millisSinceEpoch);
+ instant = Instant.ofEpochMilli(millisSinceEpoch);
}
public void advanceMillis(long millis) { advance(Duration.ofMillis(millis)); }
public void advanceSeconds(long seconds) { advance(Duration.ofSeconds(seconds)); }
public void advanceMinutes(long minutes) { advance(Duration.ofMinutes(minutes)); }
public void advance(Duration duration) {
- durationSinceEpoch = durationSinceEpoch.plus(duration);
+ instant = instant.plus(duration);
+ }
+
+ @Override
+ public Instant currentTime() {
+ return instant;
}
@Override
public long currentTimeMillis() {
- return durationSinceEpoch.toMillis();
+ return instant.toEpochMilli();
}
}
diff --git a/logd/src/logd/CMakeLists.txt b/logd/src/logd/CMakeLists.txt
index 92f70ef9102..cc73b51f0b1 100644
--- a/logd/src/logd/CMakeLists.txt
+++ b/logd/src/logd/CMakeLists.txt
@@ -8,10 +8,7 @@ protobuf_generate_cpp(logd_PROTOBUF_SRCS logd_PROTOBUF_HDRS ../../../logserver/s
vespa_add_source_target(protobufgen_logd DEPENDS ${logd_PROTOBUF_SRCS} ${logd_PROTOBUF_HDRS})
-# protoc-generated files emit compiler warnings that we normally treat as errors.
-if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- set_source_files_properties(${logd_PROTOBUF_SRCS} PROPERTIES COMPILE_FLAGS "-Wno-array-bounds -Wno-suggest-override")
-endif()
+vespa_suppress_warnings_for_protobuf_sources(SOURCES ${logd_PROTOBUF_SRCS})
vespa_add_library(logd STATIC
SOURCES
diff --git a/model-integration/src/test/models/onnx/simple/simple.onnx b/model-integration/src/test/models/onnx/simple/simple.onnx
index 41b458451d0..88ed0ef23f0 100644
--- a/model-integration/src/test/models/onnx/simple/simple.onnx
+++ b/model-integration/src/test/models/onnx/simple/simple.onnx
@@ -1,10 +1,10 @@
- simple.py:ã
+ simple.py:ã
0
query_tensor
attribute_tensormatmul"MatMul
"
matmul
- bias_tensoroutput"addsimple_scoringZ
+ bias_tensoroutput"Addsimple_scoringZ
query_tensor


@@ -20,4 +20,4 @@
output


-B \ No newline at end of file
+B \ No newline at end of file
diff --git a/model-integration/src/test/models/onnx/simple/simple.py b/model-integration/src/test/models/onnx/simple/simple.py
index 878cf1c928e..512a2d75125 100755
--- a/model-integration/src/test/models/onnx/simple/simple.py
+++ b/model-integration/src/test/models/onnx/simple/simple.py
@@ -14,7 +14,7 @@ nodes = [
['matmul'],
),
helper.make_node(
- 'add',
+ 'Add',
['matmul', 'bias_tensor'],
['output'],
),
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
index 27731159e9f..a02043aea78 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
@@ -127,8 +127,8 @@ public class Autoscaler {
public static boolean unstable(List<Node> nodes) {
return nodes.stream().anyMatch(node -> node.status().wantToRetire() ||
- node.allocation().get().membership().retired() ||
- node.allocation().get().isRemovable());
+ node.allocation().get().membership().retired() ||
+ node.allocation().get().isRemovable());
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
index 20258e7947b..ff9015863e9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/SpareCapacityMaintainer.java
@@ -87,6 +87,9 @@ public class SpareCapacityMaintainer extends NodeRepositoryMaintainer {
// Report with the assumption this will eventually succeed to avoid alerting before we're stuck
spareHostCapacity++;
}
+ else {
+ success = false;
+ }
}
metric.set("spareHostCapacity", spareHostCapacity, null);
}
diff --git a/parent/pom.xml b/parent/pom.xml
index c2fab3da5d9..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>
@@ -770,8 +764,9 @@
<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>
- <maven-compiler-plugin.version>3.8.0</maven-compiler-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>
<maven-enforcer-plugin.version>3.0.0-M2</maven-enforcer-plugin.version>
diff --git a/processing/abi-spec.json b/processing/abi-spec.json
index 8f77672faec..a354787b491 100644
--- a/processing/abi-spec.json
+++ b/processing/abi-spec.json
@@ -1,4 +1,17 @@
{
+ "com.yahoo.processing.IllegalInputException": {
+ "superClass": "java.lang.IllegalArgumentException",
+ "interfaces": [],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>(java.lang.String)",
+ "public void <init>(java.lang.Throwable)",
+ "public void <init>(java.lang.String, java.lang.Throwable)"
+ ],
+ "fields": []
+ },
"com.yahoo.processing.Processor": {
"superClass": "com.yahoo.component.chain.ChainedComponent",
"interfaces": [],
diff --git a/processing/src/main/java/com/yahoo/processing/IllegalInputException.java b/processing/src/main/java/com/yahoo/processing/IllegalInputException.java
new file mode 100644
index 00000000000..3f1605860ed
--- /dev/null
+++ b/processing/src/main/java/com/yahoo/processing/IllegalInputException.java
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.processing;
+
+/**
+ * Thrown on illegal input received from the requesting client.
+ * Use this instead of the superclass, IllegalArgumentException
+ * to signal illegal input to the client without causing logging and stack traces,
+ *
+ * @author bratseth
+ */
+public class IllegalInputException extends IllegalArgumentException {
+
+ public IllegalInputException(String message) {
+ super(message);
+ }
+
+ public IllegalInputException(Throwable cause) {
+ super(cause);
+ }
+
+ public IllegalInputException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/processing/src/main/java/com/yahoo/processing/request/CloneHelper.java b/processing/src/main/java/com/yahoo/processing/request/CloneHelper.java
index 93b7f88f5a7..837ff3db295 100644
--- a/processing/src/main/java/com/yahoo/processing/request/CloneHelper.java
+++ b/processing/src/main/java/com/yahoo/processing/request/CloneHelper.java
@@ -84,11 +84,11 @@ public class CloneHelper {
if (object instanceof FreezableClass)
return ((FreezableClass)object).clone();
else if (object instanceof PublicCloneable)
- return ((PublicCloneable)object).clone();
+ return ((PublicCloneable<?>)object).clone();
else if (object instanceof LinkedList)
- return ((LinkedList) object).clone();
+ return ((LinkedList<?>) object).clone();
else if (object instanceof ArrayList)
- return ((ArrayList) object).clone();
+ return ((ArrayList<?>) object).clone();
try {
Method cloneMethod = cloneMethodCache.get(object);
diff --git a/processing/src/main/java/com/yahoo/processing/response/DefaultIncomingData.java b/processing/src/main/java/com/yahoo/processing/response/DefaultIncomingData.java
index 60e60796afe..c436f92f78b 100644
--- a/processing/src/main/java/com/yahoo/processing/response/DefaultIncomingData.java
+++ b/processing/src/main/java/com/yahoo/processing/response/DefaultIncomingData.java
@@ -1,7 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.processing.response;
-import com.google.common.util.concurrent.ExecutionList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.yahoo.collections.Tuple2;
@@ -26,14 +25,10 @@ public class DefaultIncomingData<DATATYPE extends Data> implements IncomingData<
private List<Tuple2<Runnable,Executor>> newDataListeners = null;
- /**
- * If this is completed no more data can be added
- */
+ /** Whether this is completed, such that no more data can be added */
private boolean complete = false;
- /**
- * Creates an instance which must be assigned an owner after creation
- */
+ /** Creates an instance which must be assigned an owner after creation */
public DefaultIncomingData() {
this(null);
}
@@ -43,9 +38,7 @@ public class DefaultIncomingData<DATATYPE extends Data> implements IncomingData<
completionFuture = SettableFuture.create();
}
- /**
- * Assigns the owner of this. Throws an exception if the owner is already set.
- */
+ /** Assigns the owner of this. Throws an exception if the owner is already set. */
public final void assignOwner(DataList<DATATYPE> owner) {
if (this.owner != null) throw new NullPointerException("Owner of " + this + " was already assigned");
this.owner = owner;
@@ -61,42 +54,32 @@ public class DefaultIncomingData<DATATYPE extends Data> implements IncomingData<
return completionFuture;
}
- /**
- * Returns whether the data in this is complete
- */
+ /** Returns whether the data in this is complete */
@Override
public synchronized boolean isComplete() {
return complete;
}
- /**
- * Add new data and mark this as completed
- */
+ /** Adds new data and marks this as completed */
@Override
public synchronized void addLast(DATATYPE data) {
addLast(Collections.singletonList(data));
}
- /**
- * Add new data without completing this
- */
+ /** Adds new data without completing this */
@Override
public synchronized void add(DATATYPE data) {
add(Collections.singletonList(data));
}
- /**
- * Add new data and mark this as completed
- */
+ /** Adds new data and marks this as completed */
@Override
public synchronized void addLast(List<DATATYPE> data) {
add(data);
markComplete();
}
- /**
- * Add new data without completing this
- */
+ /** Adds new data without completing this */
@Override
public synchronized void add(List<DATATYPE> data) {
if (complete) throw new IllegalStateException("Attempted to add data to completed " + this);
@@ -105,9 +88,7 @@ public class DefaultIncomingData<DATATYPE extends Data> implements IncomingData<
notifyDataListeners();
}
- /**
- * Mark this as completed and notify any listeners
- */
+ /** Marks this as completed and notify any listeners */
@Override
public synchronized void markComplete() {
complete = true;
@@ -115,7 +96,7 @@ public class DefaultIncomingData<DATATYPE extends Data> implements IncomingData<
}
/**
- * Get and remove all the data currently available in this.
+ * Gets and removes all the data currently available in this.
* The returned list is a modifiable fresh instance owned by the caller.
*/
public synchronized List<DATATYPE> drain() {
diff --git a/searchcore/src/tests/proton/matching/query_test.cpp b/searchcore/src/tests/proton/matching/query_test.cpp
index 6fbd43eabbe..7cc11b0dc0c 100644
--- a/searchcore/src/tests/proton/matching/query_test.cpp
+++ b/searchcore/src/tests/proton/matching/query_test.cpp
@@ -698,7 +698,7 @@ void Test::requireThatQueryGluesEverythingTogether() {
ASSERT_TRUE(search.get());
}
-void checkQueryAddsLocation(Test &test, const string &loc_string) {
+void checkQueryAddsLocation(Test &test, const string &loc_in, const string &loc_out) {
fef_test::IndexEnvironment index_environment;
FieldInfo field_info(FieldType::INDEX, CollectionType::SINGLE, field, 0);
index_environment.getFields().push_back(field_info);
@@ -712,11 +712,11 @@ void checkQueryAddsLocation(Test &test, const string &loc_string) {
Query query;
query.buildTree(stack_dump,
- loc_field + ":" + loc_string,
+ loc_field + ":" + loc_in,
ViewResolver(), index_environment);
vector<const ITermData *> term_data;
query.extractTerms(term_data);
- test.EXPECT_EQUAL(1u, term_data.size());
+ test.EXPECT_EQUAL(2u, term_data.size());
FakeRequestContext requestContext;
FakeSearchContext context;
@@ -729,9 +729,9 @@ void checkQueryAddsLocation(Test &test, const string &loc_string) {
query.fetchPostings();
SearchIterator::UP search = query.createSearch(*md);
test.ASSERT_TRUE(search.get());
- if (!test.EXPECT_NOT_EQUAL(string::npos, search->asString().find(loc_string))) {
- fprintf(stderr, "search (missing loc_string '%s'): %s",
- loc_string.c_str(), search->asString().c_str());
+ if (!test.EXPECT_NOT_EQUAL(string::npos, search->asString().find(loc_out))) {
+ fprintf(stderr, "search (missing loc_out '%s'): %s",
+ loc_out.c_str(), search->asString().c_str());
}
}
@@ -790,11 +790,15 @@ void Test::requireThatLocationIsAddedTheCorrectPlace() {
}
void Test::requireThatQueryAddsLocation() {
- checkQueryAddsLocation(*this, "(2,10,10,3,0,1,0,0)");
+ checkQueryAddsLocation(*this, "(2,10,10,3,0,1,0,0)", "{p:{x:10,y:10},r:3,b:{x:[7,13],y:[7,13]}}");
+ checkQueryAddsLocation(*this, "{p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,b:{x:[7,13],y:[7,13]}}");
+ checkQueryAddsLocation(*this, "{b:{x:[6,11],y:[8,15]},p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,b:{x:[7,11],y:[8,13]}}");
+ checkQueryAddsLocation(*this, "{a:12345,b:{x:[8,10],y:[8,10]},p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,a:12345,b:{x:[8,10],y:[8,10]}}");
}
void Test::requireThatQueryAddsLocationCutoff() {
- checkQueryAddsLocation(*this, "[2,10,10,20,20]");
+ checkQueryAddsLocation(*this, "[2,10,11,23,24]", "{b:{x:[10,23],y:[11,24]}}");
+ checkQueryAddsLocation(*this, "{b:{y:[11,24],x:[10,23]}}", "{b:{x:[10,23],y:[11,24]}}");
}
void
diff --git a/searchcore/src/tests/proton/matching/termdataextractor_test.cpp b/searchcore/src/tests/proton/matching/termdataextractor_test.cpp
index 36c34e38a04..fb338d409e7 100644
--- a/searchcore/src/tests/proton/matching/termdataextractor_test.cpp
+++ b/searchcore/src/tests/proton/matching/termdataextractor_test.cpp
@@ -103,8 +103,8 @@ void Test::requireThatTermsAreAdded() {
vector<const ITermData *> term_data;
TermDataExtractor::extractTerms(*node, term_data);
- EXPECT_EQUAL(7u, term_data.size());
- for (int i = 0; i < 7; ++i) {
+ EXPECT_EQUAL(8u, term_data.size());
+ for (int i = 0; i < 8; ++i) {
EXPECT_EQUAL(id[i], term_data[i]->getUniqueId());
EXPECT_EQUAL(1u, term_data[i]->numFields());
}
@@ -118,8 +118,8 @@ void Test::requireThatAViewWithTwoFieldsGivesOneTermDataPerTerm() {
vector<const ITermData *> term_data;
TermDataExtractor::extractTerms(*node, term_data);
- EXPECT_EQUAL(7u, term_data.size());
- for (int i = 0; i < 7; ++i) {
+ EXPECT_EQUAL(8u, term_data.size());
+ for (int i = 0; i < 8; ++i) {
EXPECT_EQUAL(id[i], term_data[i]->getUniqueId());
EXPECT_EQUAL(2u, term_data[i]->numFields());
}
diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.cpp b/searchcore/src/vespa/searchcore/proton/matching/query.cpp
index 65959e6e6de..994e26081e7 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/query.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/query.cpp
@@ -83,7 +83,7 @@ GeoLocationSpec parse_location_string(string str) {
return empty;
}
GeoLocationParser parser;
- if (parser.parseOldFormatWithField(str)) {
+ if (parser.parseWithField(str)) {
auto attr_name = PositionDataType::getZCurveFieldName(parser.getFieldName());
return GeoLocationSpec{attr_name, parser.getGeoLocation()};
} else {
diff --git a/searchcore/src/vespa/searchcore/proton/matching/termdataextractor.cpp b/searchcore/src/vespa/searchcore/proton/matching/termdataextractor.cpp
index c0007ae2bda..673355f9354 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/termdataextractor.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/termdataextractor.cpp
@@ -29,8 +29,6 @@ public:
}
}
- void visit(ProtonLocationTerm &) override {}
-
virtual void visit(ProtonNodeTypes::AndNot &n) override {
assert(n.getChildren().size() > 0);
n.getChildren()[0]->accept(*this);
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..d142733041e 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,16 +17,22 @@ 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) {
+bool is_parseable(const char *str, bool with_field = false) {
GeoLocationParser parser;
- return parser.parseOldFormat(str);
+ if (with_field) {
+ return parser.parseWithField(str);
+ }
+ return parser.parseNoField(str);
}
-GeoLocation parse(const char *str) {
+GeoLocation parse(const std::string &str, bool with_field = false) {
GeoLocationParser parser;
- EXPECT_TRUE(parser.parseOldFormat(str));
+ if (with_field) {
+ EXPECT_TRUE(parser.parseWithField(str));
+ } else {
+ EXPECT_TRUE(parser.parseNoField(str));
+ }
return parser.getGeoLocation();
}
@@ -40,6 +47,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("{b:{x:[10,30],y:[20,40]}}"));
+ EXPECT_TRUE(is_parseable("{b:{}}"));
+ EXPECT_TRUE(is_parseable("{b:[]}"));
+ EXPECT_TRUE(is_parseable("{b:10,b:20}"));
+ EXPECT_TRUE(is_parseable("{b:[10, 20, 30, 40]}"));
+ EXPECT_FALSE(is_parseable("{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 +68,147 @@ TEST(GeoLocationParserTest, malformed_circles_are_not_parseable) {
EXPECT_FALSE(is_parseable("(10,20,5)"));
}
+TEST(GeoLocationParserTest, new_circle_formats) {
+ EXPECT_TRUE(is_parseable("{p:{x:10,y:20}}"));
+ EXPECT_TRUE(is_parseable("{p:{x:10,y:20},r:5}"));
+ EXPECT_TRUE(is_parseable("{p:{x:10, y:10}, r:5}"));
+ EXPECT_TRUE(is_parseable("{'p':{y:20,x:10},'r':5}"));
+ EXPECT_TRUE(is_parseable("{\n \"p\": { \"x\": 10, \"y\": 20},\n \"r\": 5\n}"));
+ // json demands colon:
+ EXPECT_FALSE(is_parseable("{p:{x:10,y:10},r=5}"));
+ // missing y -> 0 default:
+ EXPECT_TRUE(is_parseable("{p:{x:10},r:5}"));
+ // unused extra fields are ignored:
+ EXPECT_TRUE(is_parseable("{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("{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("{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("{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("{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("{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("{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("{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("{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("{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("{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 +460,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(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(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(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(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/tests/tensor/distance_functions/distance_functions_test.cpp b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
index 082d04f104b..9d240bc688a 100644
--- a/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
+++ b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp
@@ -25,7 +25,7 @@ void verify_geo_miles(const DistanceFunction *dist_fun,
double abstract_distance = dist_fun->calc(t1, t2);
double raw_score = dist_fun->to_rawscore(abstract_distance);
double m = ((1.0/raw_score)-1.0);
- double d_miles = m / 1609.344;
+ double d_miles = m / 1.609344;
EXPECT_GE(d_miles, exp_miles*0.99);
EXPECT_LE(d_miles, exp_miles*1.01);
}
@@ -159,7 +159,7 @@ TEST(GeoDegreesTest, gives_expected_score)
double g63_a = geodeg->calc(t(g6_trd), t(g3_osl));
double g63_r = geodeg->to_rawscore(g63_a);
- double g63_km = ((1.0/g63_r)-1.0) *.001;
+ double g63_km = ((1.0/g63_r)-1.0);
EXPECT_GT(g63_km, 350);
EXPECT_LT(g63_km, 375);
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..7d793f9eb55 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
@@ -58,19 +63,6 @@ GeoLocationParser::correctDimensionalitySkip(const char * &p) {
}
bool
-GeoLocationParser::parseOldFormatWithField(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 parseOldFormat(only_loc);
-}
-
-bool
GeoLocationParser::parseOldFormat(const std::string &locStr)
{
bool foundBoundingBox = false;
@@ -179,9 +171,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..e1a68163fbb 100644
--- a/searchlib/src/vespa/searchlib/common/geo_location_parser.h
+++ b/searchlib/src/vespa/searchlib/common/geo_location_parser.h
@@ -17,8 +17,8 @@ class GeoLocationParser
public:
GeoLocationParser();
- bool parseOldFormat(const std::string &locStr);
- bool parseOldFormatWithField(const std::string &str);
+ bool parseNoField(const std::string &locStr);
+ bool parseWithField(const std::string &locStr);
std::string getFieldName() const { return _field_name; }
GeoLocation getGeoLocation() const;
@@ -42,6 +42,8 @@ private:
const char *_parseError;
bool correctDimensionalitySkip(const char * &p);
+ bool parseJsonFormat(const std::string &locStr);
+ bool parseOldFormat(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/engine/CMakeLists.txt b/searchlib/src/vespa/searchlib/engine/CMakeLists.txt
index 082af18d32b..570118de0af 100644
--- a/searchlib/src/vespa/searchlib/engine/CMakeLists.txt
+++ b/searchlib/src/vespa/searchlib/engine/CMakeLists.txt
@@ -5,11 +5,7 @@ protobuf_generate_cpp(searchlib_engine_PROTOBUF_SRCS searchlib_engine_PROTOBUF_H
vespa_add_source_target(protobufgen_searchlib_engine DEPENDS ${searchlib_engine_PROTOBUF_SRCS} ${searchlib_engine_PROTOBUF_HDRS})
-# protoc-generated files emit compiler warnings that we normally treat as errors.
-if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- set_source_files_properties(${searchlib_engine_PROTOBUF_SRCS}
- PROPERTIES COMPILE_FLAGS "-Wno-array-bounds -Wno-suggest-override")
-endif()
+vespa_suppress_warnings_for_protobuf_sources(SOURCES ${searchlib_engine_PROTOBUF_SRCS})
vespa_add_library(searchlib_engine OBJECT
SOURCES
diff --git a/searchlib/src/vespa/searchlib/features/distancefeature.cpp b/searchlib/src/vespa/searchlib/features/distancefeature.cpp
index 78a94c4abe0..d2431ccc06b 100644
--- a/searchlib/src/vespa/searchlib/features/distancefeature.cpp
+++ b/searchlib/src/vespa/searchlib/features/distancefeature.cpp
@@ -83,8 +83,8 @@ feature_t
DistanceExecutor::calculateDistance(uint32_t docId)
{
_best_index = -1.0;
- _best_x = 0.0;
- _best_y = 0.0;
+ _best_x = -180.0 * 1.0e6;
+ _best_y = 90.0 * 1.0e6;
if ((! _locations.empty()) && (_pos != nullptr)) {
LOG(debug, "calculate 2D Z-distance from %zu locations", _locations.size());
return calculate2DZDistance(docId);
@@ -135,8 +135,8 @@ DistanceExecutor::execute(uint32_t docId)
{
outputs().set_number(0, calculateDistance(docId));
outputs().set_number(1, _best_index);
- outputs().set_number(2, _best_y * 0.000001); // latitude
- outputs().set_number(3, _best_x * 0.000001); // longitude
+ outputs().set_number(2, _best_y * 1.0e-6); // latitude
+ outputs().set_number(3, _best_x * 1.0e-6); // longitude
}
const feature_t DistanceExecutor::DEFAULT_DISTANCE(6400000000.0);
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/fef/termfieldmatchdata.h b/searchlib/src/vespa/searchlib/fef/termfieldmatchdata.h
index efa2e3f5bfa..633d85f98df 100644
--- a/searchlib/src/vespa/searchlib/fef/termfieldmatchdata.h
+++ b/searchlib/src/vespa/searchlib/fef/termfieldmatchdata.h
@@ -260,7 +260,7 @@ public:
* This indicates if this instance is actually used for ranking or not.
* @return true if it is not needed.
*/
- bool isNotNeeded() const { return ((_flags & (UNPACK_NORMAL_FEATURES_FLAG | UNPACK_INTERLEAVED_FEATURES_FLAG)) == 0u); }
+ bool isNotNeeded() const { return ((_flags & (UNPACK_NORMAL_FEATURES_FLAG | UNPACK_INTERLEAVED_FEATURES_FLAG)) == 0u); }
bool needs_normal_features() const { return ((_flags & UNPACK_NORMAL_FEATURES_FLAG) != 0u); }
diff --git a/searchlib/src/vespa/searchlib/query/tree/location.cpp b/searchlib/src/vespa/searchlib/query/tree/location.cpp
index 6e678f9e682..9b45ba18b97 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();
}
-vespalib::asciistream &operator<<(vespalib::asciistream &out, const Location &loc) {
- return out << loc.getOldFormatString();
+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.getJsonFormatString();
}
+
+} // 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/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h b/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h
index a7e00d41555..66702fcd85c 100644
--- a/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h
+++ b/searchlib/src/vespa/searchlib/query/tree/stackdumpquerycreator.h
@@ -144,7 +144,9 @@ private:
t = &builder.addSuffixTerm(term, view, id, weight);
} else if (type == ParseItem::ITEM_GEO_LOCATION_TERM) {
search::common::GeoLocationParser parser;
- parser.parseOldFormat(term);
+ if (! parser.parseNoField(term)) {
+ LOG(warning, "invalid geo location term '%s'", term.data());
+ }
Location loc(parser.getGeoLocation());
t = &builder.addLocationTerm(loc, view, id, weight);
} else if (type == ParseItem::ITEM_NUMTERM) {
diff --git a/searchlib/src/vespa/searchlib/tensor/distance_functions.h b/searchlib/src/vespa/searchlib/tensor/distance_functions.h
index 7e75920619f..f88b239885f 100644
--- a/searchlib/src/vespa/searchlib/tensor/distance_functions.h
+++ b/searchlib/src/vespa/searchlib/tensor/distance_functions.h
@@ -165,8 +165,8 @@ public:
}
double to_rawscore(double distance) const override {
double hav_diff = sqrt(distance);
- // distance in meters:
- double d = 2 * asin(hav_diff) * 6371008.8; // Earth mean radius
+ // distance in kilometers:
+ double d = 2 * asin(hav_diff) * 6371.0088; // Earth mean radius
return 1.0 / (1.0 + d);
}
double calc_with_limit(const vespalib::tensor::TypedCells& lhs,
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/docsumstate.cpp b/searchsummary/src/vespa/searchsummary/docsummary/docsumstate.cpp
index 1f9b553b56a..822017e0bdf 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/docsumstate.cpp
+++ b/searchsummary/src/vespa/searchsummary/docsummary/docsumstate.cpp
@@ -76,7 +76,7 @@ GetDocsumsState::parse_locations()
assert(_parsedLocations.empty()); // only allowed to call this once
if (! _args.getLocation().empty()) {
GeoLocationParser parser;
- if (parser.parseOldFormatWithField(_args.getLocation())) {
+ if (parser.parseWithField(_args.getLocation())) {
auto view = parser.getFieldName();
auto attr_name = PositionDataType::getZCurveFieldName(view);
GeoLocationSpec spec{attr_name, parser.getGeoLocation()};
@@ -94,7 +94,7 @@ GetDocsumsState::parse_locations()
vespalib::string view = iterator.getIndexName();
vespalib::string term = iterator.getTerm();
GeoLocationParser parser;
- if (parser.parseOldFormat(term)) {
+ if (parser.parseNoField(term)) {
auto attr_name = PositionDataType::getZCurveFieldName(view);
GeoLocationSpec spec{attr_name, parser.getGeoLocation()};
_parsedLocations.push_back(spec);
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/filestorage/filestorhandlerimpl.cpp b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
index f536def28a0..4df2b5e591b 100644
--- a/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
+++ b/storage/src/vespa/storage/persistence/filestorage/filestorhandlerimpl.cpp
@@ -14,9 +14,6 @@
#include <vespa/storageapi/message/stat.h>
#include <vespa/vespalib/stllike/hash_map.hpp>
#include <vespa/vespalib/util/exceptions.h>
-#ifndef XXH_INLINE_ALL
-# define XXH_INLINE_ALL // Let XXH64 be inlined for fixed hash size (bucket ID)
-#endif
#include <xxhash.h>
#include <vespa/log/log.h>
diff --git a/storage/src/vespa/storage/persistence/testandsethelper.cpp b/storage/src/vespa/storage/persistence/testandsethelper.cpp
index 1dbcbcc3fc6..57586249817 100644
--- a/storage/src/vespa/storage/persistence/testandsethelper.cpp
+++ b/storage/src/vespa/storage/persistence/testandsethelper.cpp
@@ -70,7 +70,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" : ""));
}
@@ -82,7 +82,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/mbusprot/CMakeLists.txt b/storageapi/src/vespa/storageapi/mbusprot/CMakeLists.txt
index 1b1e224f034..b749844775d 100644
--- a/storageapi/src/vespa/storageapi/mbusprot/CMakeLists.txt
+++ b/storageapi/src/vespa/storageapi/mbusprot/CMakeLists.txt
@@ -9,11 +9,8 @@ PROTOBUF_GENERATE_CPP(storageapi_PROTOBUF_SRCS storageapi_PROTOBUF_HDRS
vespa_add_source_target(protobufgen_storageapi_mbusprot DEPENDS ${storageapi_PROTOBUF_SRCS} ${storageapi_PROTOBUF_HDRS})
-# protoc-generated files emit compiler warnings that we normally treat as errors.
-# Instead of rolling our own compiler plugin we'll pragmatically disable the noise.
-if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
- set_source_files_properties(${storageapi_PROTOBUF_SRCS} PROPERTIES COMPILE_FLAGS "-Wno-array-bounds -Wno-suggest-override -Wno-inline")
-endif()
+vespa_suppress_warnings_for_protobuf_sources(SOURCES ${storageapi_PROTOBUF_SRCS})
+
# protoc explicitly annotates methods with inline, which triggers -Werror=inline when
# the header file grows over a certain size.
set_source_files_properties(protocolserialization7.cpp PROPERTIES COMPILE_FLAGS "-Wno-inline")
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/streamingvisitors/src/vespa/searchvisitor/queryenvironment.cpp b/streamingvisitors/src/vespa/searchvisitor/queryenvironment.cpp
index 06bdb9f69bb..383f6c3d44b 100644
--- a/streamingvisitors/src/vespa/searchvisitor/queryenvironment.cpp
+++ b/streamingvisitors/src/vespa/searchvisitor/queryenvironment.cpp
@@ -26,7 +26,7 @@ parseLocation(const string & location_str)
return fefLocations;
}
GeoLocationParser locationParser;
- if (!locationParser.parseOldFormatWithField(location_str)) {
+ if (!locationParser.parseWithField(location_str)) {
LOG(warning, "Location parse error (location: '%s'): %s. Location ignored.",
location_str.c_str(), locationParser.getParseError());
return fefLocations;
diff --git a/tenant-base/pom.xml b/tenant-base/pom.xml
index addaedec7df..ed5c32563c7 100644
--- a/tenant-base/pom.xml
+++ b/tenant-base/pom.xml
@@ -35,7 +35,7 @@
<vespaversion>${project.version}</vespaversion>
<test-framework.version>${project.version}</test-framework.version>
<target_jdk_version>11</target_jdk_version>
- <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
+ <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>
<junit.version>5.6.2</junit.version> <!-- Keep in sync with hosted-tenant-base and tenant-cd until all direct use is removed -->
<endpoint>https://api.vespa-external.aws.oath.cloud:4443</endpoint>
diff --git a/vespa-hadoop/pom.xml b/vespa-hadoop/pom.xml
index 7e1a8d832b2..794eb038137 100644
--- a/vespa-hadoop/pom.xml
+++ b/vespa-hadoop/pom.xml
@@ -198,7 +198,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.0</version>
+ <version>3.8.1</version>
<configuration>
<jdkToolchain>
<version>${java.version}</version>
diff --git a/vespalib/src/vespa/vespalib/testkit/test_master.hpp b/vespalib/src/vespa/vespalib/testkit/test_master.hpp
index fc163c8d14e..8a5f7eb337b 100644
--- a/vespalib/src/vespa/vespalib/testkit/test_master.hpp
+++ b/vespalib/src/vespa/vespalib/testkit/test_master.hpp
@@ -4,6 +4,15 @@
namespace vespalib {
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 9
+// cf. https://cplusplus.github.io/LWG/issue2221
+template<class charT, class traits>
+std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, nullptr_t)
+{
+ return os << (void*) nullptr;
+}
+#endif
+
template<class A, class B, class OP>
bool
TestMaster::compare(const char *file, uint32_t line,