sortOptions = sortOption.getEntries().stream()
- .map(this::mapSort)
- .collect(Collectors.toList());
- aggregationBuilder.sortOptions(sortOptions);
- }
-
- @Override
- public void visit(final Option option) {
- // not required yet
- }
-
- private SortOption mapSort(final SortOptionEntry entry) {
- return new SortOption(determineSortField(entry.getPropertyPath()), determineSortDirection(entry.getOrder()));
- }
-
- private SortFieldExpression determineSortField(final CharSequence key) {
- return fieldExpressionFactory.sortBy(key.toString());
- }
-
- private static SortDirection determineSortDirection(final SortOptionEntry.SortOrder order) {
- return order == SortOptionEntry.SortOrder.ASC ? SortDirection.ASC : SortDirection.DESC;
- }
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/AggregationQueryActor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/AggregationQueryActor.java
deleted file mode 100644
index c964a28c6e..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/AggregationQueryActor.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.query;
-
-
-import java.util.Set;
-import java.util.function.Consumer;
-
-import org.eclipse.ditto.model.base.exceptions.InvalidRqlExpressionException;
-import org.eclipse.ditto.model.base.headers.DittoHeaders;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-import org.eclipse.ditto.model.query.criteria.CriteriaFactory;
-import org.eclipse.ditto.model.query.expression.ThingsFieldExpressionFactory;
-import org.eclipse.ditto.model.query.filter.EnsureMonotonicityVisitor;
-import org.eclipse.ditto.model.query.filter.QueryFilterCriteriaFactory;
-import org.eclipse.ditto.model.rql.ParserException;
-import org.eclipse.ditto.model.thingsearchparser.RqlOptionParser;
-import org.eclipse.ditto.services.models.thingsearch.commands.sudo.SudoCountThings;
-import org.eclipse.ditto.services.thingsearch.persistence.read.AggregationBuilder;
-import org.eclipse.ditto.services.thingsearch.persistence.read.AggregationBuilderFactory;
-import org.eclipse.ditto.services.thingsearch.persistence.read.PolicyRestrictedSearchAggregation;
-import org.eclipse.ditto.services.utils.akka.LogUtil;
-import org.eclipse.ditto.signals.commands.base.Command;
-import org.eclipse.ditto.signals.commands.thingsearch.exceptions.InvalidOptionException;
-import org.eclipse.ditto.signals.commands.thingsearch.query.CountThings;
-import org.eclipse.ditto.signals.commands.thingsearch.query.QueryThings;
-
-import akka.actor.AbstractActor;
-import akka.actor.Props;
-import akka.event.DiagnosticLoggingAdapter;
-import akka.japi.Creator;
-import akka.japi.pf.ReceiveBuilder;
-
-/**
- * Actor handling the parsing of search queries. It accepts {@link CountThings} and {@link QueryThings} commands and
- * responses with a corresponding {@link PolicyRestrictedSearchAggregation}.
- *
- * This actor receives only messages which where emitted by API v. 2 requests.
- */
-public final class AggregationQueryActor extends AbstractActor {
-
- /**
- * The name of this actor in the system.
- */
- public static final String ACTOR_NAME = "aggregationQueryActor";
-
- private final DiagnosticLoggingAdapter logger = LogUtil.obtain(this);
-
- private final ThingsFieldExpressionFactory fieldExpressionFactory;
- private final QueryFilterCriteriaFactory queryFilterCriteriaFactory;
- private final AggregationBuilderFactory aggregationBuilderFactory;
- private final RqlOptionParser rqlOptionParser;
-
- private AggregationQueryActor(final CriteriaFactory criteriaFactory,
- final ThingsFieldExpressionFactory fieldExpressionFactory,
- final AggregationBuilderFactory aggregationBuilderFactory) {
- this.fieldExpressionFactory = fieldExpressionFactory;
- this.aggregationBuilderFactory = aggregationBuilderFactory;
- this.queryFilterCriteriaFactory = new QueryFilterCriteriaFactory(criteriaFactory, fieldExpressionFactory);
- rqlOptionParser = new RqlOptionParser();
- }
-
- /**
- * Creates Akka configuration object Props for this AggregationQueryActor.
- *
- * @param criteriaFactory a factory to create criteria.
- * @param fieldExpressionFactory a factory to retrieve things field expressions.
- * @param aggregationBuilderFactory a factory to create a query builder.
- * @return the Akka configuration Props object.
- */
- public static Props props(final CriteriaFactory criteriaFactory,
- final ThingsFieldExpressionFactory fieldExpressionFactory,
- final AggregationBuilderFactory aggregationBuilderFactory) {
- return Props.create(AggregationQueryActor.class, new Creator() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public AggregationQueryActor create() {
- return new AggregationQueryActor(criteriaFactory, fieldExpressionFactory, aggregationBuilderFactory);
- }
- });
- }
-
- @Override
- public Receive createReceive() {
- return ReceiveBuilder.create()
- .match(CountThings.class, cmd -> catchDittoRuntimeException(this::handleCountThings, cmd))
- .match(QueryThings.class, cmd -> catchDittoRuntimeException(this::handleQueryThings, cmd))
- .match(SudoCountThings.class, cmd -> catchDittoRuntimeException(this::handleSudoCountThings, cmd))
- .matchAny(any -> {
- logger.warning("Got unknown message '{}'", any);
- getContext().stop(getSelf());
- }).build();
- }
-
- private void catchDittoRuntimeException(final Consumer consumer, final T command) {
- try {
- consumer.accept(command);
- } catch (final InvalidRqlExpressionException | InvalidOptionException e) {
- logger.warning("Error when creating PolicyRestrictedSearchAggregation from Command: {}", e.getMessage());
- getSender().tell(e, getSelf());
- }
- }
-
- private void handleCountThings(final CountThings command) {
- final Criteria filterCriteria;
- final DittoHeaders dittoHeaders = command.getDittoHeaders();
- final Set namespaces = command.getNamespaces().orElse(null);
-
- if (namespaces == null) {
- filterCriteria = queryFilterCriteriaFactory.filterCriteria(
- command.getFilter().orElse(null), dittoHeaders);
- } else {
- filterCriteria = queryFilterCriteriaFactory.filterCriteriaRestrictedByNamespaces(
- command.getFilter().orElse(null),
- dittoHeaders, namespaces);
- }
-
- EnsureMonotonicityVisitor.apply(filterCriteria, dittoHeaders);
-
- final AggregationBuilder aggregationBuilder = aggregationBuilderFactory.newCountBuilder(filterCriteria)
- .authorizationSubjects(dittoHeaders.getAuthorizationContext().getAuthorizationSubjectIds());
-
- getSender().tell(aggregationBuilder.build(), getSelf());
- }
-
- private void handleQueryThings(final QueryThings command) {
- final Criteria filterCriteria;
- final DittoHeaders dittoHeaders = command.getDittoHeaders();
- final Set namespaces = command.getNamespaces().orElse(null);
-
- if (namespaces == null) {
- filterCriteria = queryFilterCriteriaFactory.filterCriteria(
- command.getFilter().orElse(null), dittoHeaders);
- } else {
- filterCriteria = queryFilterCriteriaFactory.filterCriteriaRestrictedByNamespaces(
- command.getFilter().orElse(null),
- dittoHeaders, namespaces);
- }
-
- EnsureMonotonicityVisitor.apply(filterCriteria, dittoHeaders);
-
- final AggregationBuilder aggregationBuilder = aggregationBuilderFactory.newBuilder(filterCriteria)
- .authorizationSubjects(dittoHeaders.getAuthorizationContext().getAuthorizationSubjectIds());
-
- command.getOptions()
- .map(optionStrings -> String.join(",", optionStrings))
- .ifPresent(options -> setOptions(options, aggregationBuilder, dittoHeaders));
-
- getSender().tell(aggregationBuilder.build(), getSelf());
- }
-
- private void handleSudoCountThings(final SudoCountThings command) {
- final Criteria criteria = queryFilterCriteriaFactory.filterCriteria(
- command.getFilter().orElse(null),
- command.getDittoHeaders());
-
- final AggregationBuilder aggregationBuilder = aggregationBuilderFactory.newCountBuilder(criteria);
- aggregationBuilder.sudo(true);
-
- getSender().tell(aggregationBuilder.build(), getSelf());
- }
-
- private void setOptions(final String options, final AggregationBuilder aggregationBuilder,
- final DittoHeaders dittoHeaders) {
- try {
- final AggregationParameterOptionVisitor visitor =
- new AggregationParameterOptionVisitor(fieldExpressionFactory,
- aggregationBuilder);
- visitor.visitAll(rqlOptionParser.parse(options));
- } catch (final ParserException | IllegalArgumentException e) {
- throw InvalidOptionException.newBuilder()
- .message(e.getMessage())
- .cause(e)
- .dittoHeaders(dittoHeaders)
- .build();
- }
- }
-
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryActor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryActor.java
deleted file mode 100644
index 611df32df4..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryActor.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.query;
-
-import static org.eclipse.ditto.model.base.json.JsonSchemaVersion.V_1;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Consumer;
-
-import org.eclipse.ditto.model.base.exceptions.InvalidRqlExpressionException;
-import org.eclipse.ditto.model.base.headers.DittoHeaders;
-import org.eclipse.ditto.model.query.Query;
-import org.eclipse.ditto.model.query.QueryBuilder;
-import org.eclipse.ditto.model.query.QueryBuilderFactory;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-import org.eclipse.ditto.model.query.criteria.CriteriaFactory;
-import org.eclipse.ditto.model.query.criteria.Predicate;
-import org.eclipse.ditto.model.query.expression.ThingsFieldExpressionFactory;
-import org.eclipse.ditto.model.query.filter.QueryFilterCriteriaFactory;
-import org.eclipse.ditto.model.rql.ParserException;
-import org.eclipse.ditto.model.thingsearchparser.RqlOptionParser;
-import org.eclipse.ditto.services.models.thingsearch.commands.sudo.SudoCountThings;
-import org.eclipse.ditto.services.models.thingsearch.query.filter.ParameterOptionVisitor;
-import org.eclipse.ditto.services.utils.akka.LogUtil;
-import org.eclipse.ditto.signals.commands.base.Command;
-import org.eclipse.ditto.signals.commands.thingsearch.exceptions.InvalidOptionException;
-import org.eclipse.ditto.signals.commands.thingsearch.query.CountThings;
-import org.eclipse.ditto.signals.commands.thingsearch.query.QueryThings;
-import org.eclipse.ditto.signals.commands.thingsearch.query.ThingSearchQueryCommand;
-
-import akka.actor.AbstractActor;
-import akka.actor.Props;
-import akka.event.DiagnosticLoggingAdapter;
-import akka.japi.Creator;
-import akka.japi.pf.ReceiveBuilder;
-
-/**
- * Actor handling the parsing of search queries. It accepts {@link CountThings} and {@link QueryThings} commands and
- * responses with a corresponding {@link Query}.
- *
- * This actor receives only messages which where emitted by API v. 1 requests.
- */
-public final class QueryActor extends AbstractActor {
-
- /**
- * The name of this actor in the system.
- */
- public static final String ACTOR_NAME = "queryActor";
-
- private final DiagnosticLoggingAdapter logger = LogUtil.obtain(this);
-
- private final QueryFilterCriteriaFactory queryFilterCriteriaFactory;
- private final ThingsFieldExpressionFactory fieldExpressionFactory;
- private final QueryBuilderFactory queryBuilderFactory;
- private final RqlOptionParser rqlOptionParser;
-
- private QueryActor(final CriteriaFactory criteriaFactory, final ThingsFieldExpressionFactory fieldExpressionFactory,
- final QueryBuilderFactory queryBuilderFactory) {
-
- this.queryFilterCriteriaFactory = new QueryFilterCriteriaFactory(criteriaFactory, fieldExpressionFactory);
- this.fieldExpressionFactory = fieldExpressionFactory;
- this.queryBuilderFactory = queryBuilderFactory;
- rqlOptionParser = new RqlOptionParser();
- }
-
- /**
- * Creates Akka configuration object Props for this QueryActor.
- *
- * @param criteriaFactory a factory to create criteria.
- * @param fieldExpressionFactory a factory to retrieve things field expressions.
- * @param queryBuilderFactory a factory to create a query builder.
- * @return the Akka configuration Props object.
- */
- public static Props props(final CriteriaFactory criteriaFactory,
- final ThingsFieldExpressionFactory fieldExpressionFactory, final QueryBuilderFactory queryBuilderFactory) {
-
- return Props.create(QueryActor.class, new Creator() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public QueryActor create() {
- return new QueryActor(criteriaFactory, fieldExpressionFactory, queryBuilderFactory);
- }
- });
- }
-
- @Override
- public Receive createReceive() {
- return ReceiveBuilder.create()
- .match(CountThings.class, cmd -> catchDittoRuntimeException(this::handleCountThings, cmd))
- .match(QueryThings.class, cmd -> catchDittoRuntimeException(this::handleQueryThings, cmd))
- .match(SudoCountThings.class, cmd -> catchDittoRuntimeException(this::handleSudoCountThings, cmd))
- .matchAny(any -> {
- logger.warning("Got unknown message '{}'", any);
- getContext().stop(getSelf());
- }).build();
- }
-
- private void catchDittoRuntimeException(final Consumer consumer, final T command) {
- try {
- consumer.accept(command);
- } catch (final InvalidRqlExpressionException | InvalidOptionException e) {
- LogUtil.enhanceLogWithCorrelationId(logger, command);
- logger.info("Error when creating Query from Command: {}", e.getMessage());
- getSender().tell(e, getSelf());
- }
- }
-
- private void handleCountThings(final CountThings command) {
- final Criteria criteria = parseCriteriaWithAuthorization(command);
- final QueryBuilder queryBuilder = queryBuilderFactory.newUnlimitedBuilder(criteria);
- getSender().tell(queryBuilder.build(), getSelf());
- }
-
- private Criteria parseCriteriaWithAuthorization(final ThingSearchQueryCommand> command) {
- final Criteria criteria;
- final DittoHeaders dittoHeaders = command.getDittoHeaders();
- final Set namespaces = command.getNamespaces().orElse(null);
- final String filter = command.getFilter().orElse(null);
- final List subjectIds = dittoHeaders.getAuthorizationContext().getAuthorizationSubjectIds();
-
- if (V_1 == command.getImplementedSchemaVersion()) {
- if (namespaces == null) {
- criteria =
- queryFilterCriteriaFactory.filterCriteriaRestrictedByAcl(filter, dittoHeaders, subjectIds);
- } else {
- criteria = queryFilterCriteriaFactory.filterCriteriaRestrictedByAclAndNamespaces(
- filter, dittoHeaders, subjectIds, namespaces);
- }
- } else {
- final CriteriaFactory cf = queryFilterCriteriaFactory.getCriteriaFactory();
- final Predicate subjectPredicate = cf.in(subjectIds);
- final Criteria globalReadsCriteria =
- cf.fieldCriteria(fieldExpressionFactory.filterByGlobalRead(), subjectPredicate);
- final Criteria aclCriteria =
- cf.fieldCriteria(fieldExpressionFactory.filterByAcl(), subjectPredicate);
- final Criteria authorizationCriteria = cf.or(Arrays.asList(globalReadsCriteria, aclCriteria));
- final Criteria filterCriteria = namespaces == null
- ? queryFilterCriteriaFactory.filterCriteria(filter, dittoHeaders)
- : queryFilterCriteriaFactory.filterCriteriaRestrictedByNamespaces(filter, dittoHeaders, namespaces);
- criteria = cf.and(Arrays.asList(authorizationCriteria, filterCriteria));
- }
-
- return criteria;
- }
-
- private void handleQueryThings(final QueryThings command) {
- final Criteria criteria = parseCriteriaWithAuthorization(command);
- final DittoHeaders dittoHeaders = command.getDittoHeaders();
-
- final QueryBuilder queryBuilder = queryBuilderFactory.newBuilder(criteria);
-
- command.getOptions()
- .map(optionStrings -> String.join(",", optionStrings))
- .ifPresent(options -> setOptions(options, queryBuilder, dittoHeaders));
-
- getSender().tell(queryBuilder.build(), getSelf());
- }
-
- private void handleSudoCountThings(final SudoCountThings command) {
- final Criteria filterCriteria = queryFilterCriteriaFactory.filterCriteria(
- command.getFilter().orElse(null), command.getDittoHeaders());
-
- final QueryBuilder queryBuilder = queryBuilderFactory.newUnlimitedBuilder(filterCriteria);
-
- getSender().tell(queryBuilder.build(), getSelf());
- }
-
- private void setOptions(final String options, final QueryBuilder queryBuilder,
- final DittoHeaders dittoHeaders) {
- try {
- final ParameterOptionVisitor visitor = new ParameterOptionVisitor(fieldExpressionFactory, queryBuilder);
- visitor.visitAll(rqlOptionParser.parse(options));
- } catch (final ParserException | IllegalArgumentException e) {
- throw InvalidOptionException.newBuilder()
- .message(e.getMessage())
- .cause(e)
- .dittoHeaders(dittoHeaders)
- .build();
- }
- }
-
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryParser.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryParser.java
new file mode 100644
index 0000000000..1a6a01f9f1
--- /dev/null
+++ b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/query/QueryParser.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.ditto.services.thingsearch.persistence.query;
+
+import java.util.Set;
+
+import org.eclipse.ditto.model.base.headers.DittoHeaders;
+import org.eclipse.ditto.model.query.Query;
+import org.eclipse.ditto.model.query.QueryBuilder;
+import org.eclipse.ditto.model.query.QueryBuilderFactory;
+import org.eclipse.ditto.model.query.criteria.Criteria;
+import org.eclipse.ditto.model.query.criteria.CriteriaFactory;
+import org.eclipse.ditto.model.query.expression.ThingsFieldExpressionFactory;
+import org.eclipse.ditto.model.query.filter.QueryFilterCriteriaFactory;
+import org.eclipse.ditto.model.rql.ParserException;
+import org.eclipse.ditto.model.thingsearchparser.RqlOptionParser;
+import org.eclipse.ditto.services.models.thingsearch.commands.sudo.SudoCountThings;
+import org.eclipse.ditto.services.models.thingsearch.query.filter.ParameterOptionVisitor;
+import org.eclipse.ditto.signals.commands.thingsearch.exceptions.InvalidOptionException;
+import org.eclipse.ditto.signals.commands.thingsearch.query.QueryThings;
+import org.eclipse.ditto.signals.commands.thingsearch.query.ThingSearchQueryCommand;
+
+/**
+ * Create Query objects from search commands.
+ */
+public final class QueryParser {
+
+ private final QueryFilterCriteriaFactory queryFilterCriteriaFactory;
+ private final ThingsFieldExpressionFactory fieldExpressionFactory;
+ private final QueryBuilderFactory queryBuilderFactory;
+ private final RqlOptionParser rqlOptionParser;
+
+ private QueryParser(final CriteriaFactory criteriaFactory,
+ final ThingsFieldExpressionFactory fieldExpressionFactory,
+ final QueryBuilderFactory queryBuilderFactory) {
+
+ this.queryFilterCriteriaFactory = new QueryFilterCriteriaFactory(criteriaFactory, fieldExpressionFactory);
+ this.fieldExpressionFactory = fieldExpressionFactory;
+ this.queryBuilderFactory = queryBuilderFactory;
+ rqlOptionParser = new RqlOptionParser();
+ }
+
+ /**
+ * Create a QueryFactory.
+ *
+ * @param criteriaFactory a factory to create criteria.
+ * @param fieldExpressionFactory a factory to retrieve things field expressions.
+ * @param queryBuilderFactory a factory to create a query builder.
+ * @return the query factory.
+ */
+ public static QueryParser of(final CriteriaFactory criteriaFactory,
+ final ThingsFieldExpressionFactory fieldExpressionFactory,
+ final QueryBuilderFactory queryBuilderFactory) {
+
+ return new QueryParser(criteriaFactory, fieldExpressionFactory, queryBuilderFactory);
+ }
+
+ /**
+ * Parses a search command into a query.
+ *
+ * @param command the search command.
+ * @return the query.
+ */
+ public Query parse(final ThingSearchQueryCommand> command) {
+ final Criteria criteria = parseCriteria(command);
+ if (command instanceof QueryThings) {
+ final QueryThings queryThings = (QueryThings) command;
+ final QueryBuilder queryBuilder = queryBuilderFactory.newBuilder(criteria);
+ queryThings.getOptions()
+ .map(optionStrings -> String.join(",", optionStrings))
+ .ifPresent(options -> setOptions(options, queryBuilder, command.getDittoHeaders()));
+ return queryBuilder.build();
+ } else {
+ return queryBuilderFactory.newUnlimitedBuilder(criteria).build();
+ }
+ }
+
+ /**
+ * Parses a SudoCountThings command into a query.
+ *
+ * @param sudoCountThings the command.
+ * @return the query.
+ */
+ public Query parseSudoCountThings(final SudoCountThings sudoCountThings) {
+ final DittoHeaders headers = sudoCountThings.getDittoHeaders();
+ final String filters = sudoCountThings.getFilter().orElse(null);
+ final Criteria criteria = queryFilterCriteriaFactory.filterCriteria(filters, headers);
+ return queryBuilderFactory.newUnlimitedBuilder(criteria).build();
+ }
+
+ private Criteria parseCriteria(final ThingSearchQueryCommand> command) {
+ final DittoHeaders headers = command.getDittoHeaders();
+ final Set namespaces = command.getNamespaces().orElse(null);
+ final String filter = command.getFilter().orElse(null);
+ if (namespaces == null) {
+ return queryFilterCriteriaFactory.filterCriteria(filter, command.getDittoHeaders());
+ } else {
+ return queryFilterCriteriaFactory.filterCriteriaRestrictedByNamespaces(filter, headers, namespaces);
+ }
+ }
+
+ private void setOptions(final String options, final QueryBuilder queryBuilder, final DittoHeaders headers) {
+ try {
+ final ParameterOptionVisitor visitor = new ParameterOptionVisitor(fieldExpressionFactory, queryBuilder);
+ visitor.visitAll(rqlOptionParser.parse(options));
+ } catch (final ParserException | IllegalArgumentException e) {
+ throw InvalidOptionException.newBuilder()
+ .message(e.getMessage())
+ .cause(e)
+ .dittoHeaders(headers)
+ .build();
+ }
+ }
+}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilder.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilder.java
deleted file mode 100644
index d33ad5dc6e..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilder.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read;
-
-import java.util.Collection;
-import java.util.List;
-
-import org.eclipse.ditto.model.query.SortOption;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-
-/**
- * Defines a Builder for a {@link PolicyRestrictedSearchAggregation}.
- */
-public interface AggregationBuilder {
-
- /**
- * Specify SortOptions. Overwrites existing SortOptions.
- *
- * @param sortOptions the SortOptions.
- * @return this builder.
- * @throws NullPointerException if {@code sortOptions} is {@code null}.
- */
- AggregationBuilder sortOptions(List sortOptions);
-
- /**
- * Limits the number of elements returned by the query.
- *
- * @param n the (maximum) number of elements to be returned.
- * @return this builder.
- */
- AggregationBuilder limit(long n);
-
- /**
- * Discards the given number of elements at the beginning of the query result.
- *
- * @param n the number of elements to be skipped.
- * @return this builder.
- */
- AggregationBuilder skip(long n);
-
- /**
- * Sets the filter criteria used for filtering things.
- *
- * @param filterCriteria the criteria.
- * @return the builder.
- * @throws NullPointerException if {@code filterCriteria} is {@code null}.
- */
- AggregationBuilder filterCriteria(Criteria filterCriteria);
-
- /**
- * Sets the authorization subjects used for filtering.
- *
- * @param authorizationSubjects the authorization subjects.
- * @return the builder.
- * @throws NullPointerException if {@code authorizationSubjects} is {@code null}.
- */
- AggregationBuilder authorizationSubjects(Collection authorizationSubjects);
-
- /**
- * Sets whether this aggregation should also consider and return as deleted marked things.
- *
- * @param withDeletedThings if {@code true} this aggration considers deleted things.
- * @return the builder.
- */
- AggregationBuilder withDeletedThings(boolean withDeletedThings);
-
- /**
- * Marks the aggregation as sudo which means that authorization subjects will not be considered when performing
- * the search.
- *
- * @param sudo if {@code true} this aggration ignores authorization subjects for filtering.
- * @return the builder.
- */
- AggregationBuilder sudo(boolean sudo);
-
- /**
- * Builds the final PolicyRestrictedSearchAggregation.
- *
- * @return the built aggregation.
- */
- PolicyRestrictedSearchAggregation build();
-
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilderFactory.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilderFactory.java
deleted file mode 100644
index e64e047b39..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/AggregationBuilderFactory.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read;
-
-import org.eclipse.ditto.model.query.criteria.Criteria;
-
-/**
- * Factory for creating a {@link AggregationBuilder}.
- */
-public interface AggregationBuilderFactory {
-
- /**
- * Creates a new {@link AggregationBuilder}.
- *
- * @param criteria the query criteria
- * @return the builder
- */
- AggregationBuilder newBuilder(Criteria criteria);
-
- /**
- * Creates a new {@link AggregationBuilder} without a default limit. Be careful to use this builder as queries created by
- * it could run for a very long time.
- *
- * @param criteria the query criteria
- * @return the builder
- */
- AggregationBuilder newCountBuilder(Criteria criteria);
-
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoHints.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoHints.java
new file mode 100644
index 0000000000..f670f11ba8
--- /dev/null
+++ b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoHints.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.ditto.services.thingsearch.persistence.read;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nullable;
+
+import org.bson.conversions.Bson;
+import org.eclipse.ditto.json.JsonField;
+import org.eclipse.ditto.json.JsonObject;
+import org.eclipse.ditto.json.JsonValue;
+import org.eclipse.ditto.services.thingsearch.persistence.Indices;
+import org.eclipse.ditto.services.utils.persistence.mongo.DittoBsonJson;
+import org.eclipse.ditto.services.utils.persistence.mongo.indices.Index;
+
+/**
+ * Package-private interface of configured hints for MongoDB.
+ */
+interface MongoHints {
+
+ /**
+ * Get a hint for the namespaces of a search query if any is configured.
+ *
+ * @param namespaces namespaces of a search query or null if none exists.
+ * @return the hint configured for one of the namespaces if any exists.
+ */
+ Optional getHint(@Nullable Set namespaces);
+
+ /**
+ * @return no hints for any namespace.
+ */
+ static MongoHints empty() {
+ return new Empty();
+ }
+
+ /**
+ * Extract hints from a JSON representation.
+ *
+ * @param jsonString text of a JSON object mapping namespaces to MongoDB hints.
+ * @return the extracted hints.
+ */
+ static MongoHints byNamespace(final String jsonString) {
+ return new ByNamespace(jsonString);
+ }
+
+ final class Empty implements MongoHints {
+
+ private Empty() {}
+
+ @Override
+ public Optional getHint(@Nullable final Set namespaces) {
+ return Optional.empty();
+ }
+ }
+
+ final class ByNamespace implements MongoHints {
+
+ private final Map map;
+
+ private ByNamespace(final String jsonString) {
+ map = JsonObject.of(jsonString)
+ .stream()
+ .collect(Collectors.toMap(JsonField::getKeyName, ByNamespace::fieldToBson));
+ }
+
+ @Override
+ public Optional getHint(@Nullable final Set namespaces) {
+ if (namespaces != null) {
+ return namespaces.stream().filter(map::containsKey).map(map::get).findAny();
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ private static Bson fieldToBson(final JsonField field) {
+ final JsonValue value = field.getValue();
+ if (value.isString()) {
+ final Optional index = getIndexByName(value.asString());
+ return index.map(Index::getKeys).orElse(null);
+ } else {
+ // it is an error if the configured hint is neither an index name nor an index spec as document.
+ final JsonObject jsonObject = value.asObject();
+ return DittoBsonJson.getInstance().parse(jsonObject);
+ }
+ }
+
+ private static Optional getIndexByName(final String name) {
+ return Indices.all().stream().filter(index -> Objects.equals(name, index.getName())).findAny();
+ }
+ }
+}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoThingsSearchPersistence.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoThingsSearchPersistence.java
index 27be333d28..f4d748e452 100644
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoThingsSearchPersistence.java
+++ b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/MongoThingsSearchPersistence.java
@@ -12,19 +12,18 @@
*/
package org.eclipse.ditto.services.thingsearch.persistence.read;
-import static com.mongodb.client.model.Filters.and;
import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull;
-import static org.eclipse.ditto.services.thingsearch.persistence.PersistenceConstants.FIELD_DELETED_FLAG;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
-import org.bson.BsonBoolean;
+import javax.annotation.Nullable;
+
import org.bson.BsonDocument;
import org.bson.Document;
import org.bson.conversions.Bson;
@@ -37,7 +36,8 @@
import org.eclipse.ditto.services.thingsearch.persistence.PersistenceConstants;
import org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors.CreateBsonVisitor;
import org.eclipse.ditto.services.thingsearch.persistence.read.query.MongoQuery;
-import org.eclipse.ditto.services.utils.persistence.mongo.DittoMongoClient;
+import org.eclipse.ditto.services.utils.config.MongoConfig;
+import org.eclipse.ditto.services.utils.persistence.mongo.BsonUtil;
import org.eclipse.ditto.services.utils.persistence.mongo.indices.IndexInitializer;
import org.eclipse.ditto.signals.commands.base.exceptions.GatewayQueryTimeExceededException;
@@ -60,40 +60,62 @@
/**
* Persistence Service Implementation for asynchronous MongoDB search.
*/
-public final class MongoThingsSearchPersistence implements ThingsSearchPersistence {
+public class MongoThingsSearchPersistence implements ThingsSearchPersistence {
private final MongoCollection collection;
+ private final LoggingAdapter log;
+
private final IndexInitializer indexInitializer;
private final Duration maxQueryTime;
- private final LoggingAdapter log;
+ private final MongoHints hints;
/**
* Initializes the things search persistence with a passed in {@code persistence}.
*
- * @param mongoClient the mongoDB persistence wrapper.
+ * @param database the mongoDB database.
* @param actorSystem the Akka ActorSystem.
*/
- public MongoThingsSearchPersistence(final DittoMongoClient mongoClient, final ActorSystem actorSystem) {
- final MongoDatabase database = mongoClient.getDefaultDatabase();
- collection = database.getCollection(PersistenceConstants.THINGS_COLLECTION_NAME).withReadPreference(
- ReadPreference.secondaryPreferred());;
- indexInitializer = IndexInitializer.of(database, ActorMaterializer.create(actorSystem));
- maxQueryTime = mongoClient.getDittoSettings().getMaxQueryTime();
+ public MongoThingsSearchPersistence(final MongoDatabase database, final ActorSystem actorSystem) {
+ // configure search persistence to stress the primary as little as possible and tolerate inconsistency
+ collection = database
+ .getCollection(PersistenceConstants.THINGS_COLLECTION_NAME)
+ .withReadPreference(ReadPreference.secondaryPreferred());
+
log = Logging.getLogger(actorSystem, getClass());
+ final ActorMaterializer materializer = ActorMaterializer.create(actorSystem);
+ indexInitializer = IndexInitializer.of(database, materializer);
+ maxQueryTime = MongoConfig.of(actorSystem.settings().config()).getMaxQueryTime();
+ hints = MongoHints.empty();
+ }
+
+ private MongoThingsSearchPersistence(
+ final MongoCollection collection,
+ final LoggingAdapter log,
+ final IndexInitializer indexInitializer,
+ final Duration maxQueryTime,
+ final MongoHints hints) {
+
+ this.collection = collection;
+ this.log = log;
+ this.indexInitializer = indexInitializer;
+ this.maxQueryTime = maxQueryTime;
+ this.hints = hints;
}
/**
- * Create a BSON filter for not-deleted entries.
+ * Create a copy of this object with configurable hints for each namespace.
*
- * @return the BSON filter.
+ * @param jsonString JSON representation of hints for queries of each namespace.
+ * @return copy of this object with hints configured.
*/
- public static BsonDocument filterNotDeleted() {
- return new BsonDocument().append(FIELD_DELETED_FLAG, BsonBoolean.FALSE);
+ public MongoThingsSearchPersistence withHintsByNamespace(final String jsonString) {
+ final MongoHints hints = MongoHints.byNamespace(jsonString);
+ return new MongoThingsSearchPersistence(collection, log, indexInitializer, maxQueryTime, hints);
}
@Override
public CompletionStage initializeIndices() {
- return indexInitializer.initialize(PersistenceConstants.THINGS_COLLECTION_NAME, Indices.Things.all())
+ return indexInitializer.initialize(PersistenceConstants.THINGS_COLLECTION_NAME, Indices.all())
.exceptionally(t -> {
log.error(t, "Index-Initialization failed: {}", t.getMessage());
return null;
@@ -113,7 +135,7 @@ public Source generateNamespaceCountReport
return Source.fromPublisher(aggregatePublisher)
.map(document -> {
- final String namespace = document.get(PersistenceConstants.FIELD_ID) != null
+ final String namespace = (document.get(PersistenceConstants.FIELD_ID) != null)
? document.get(PersistenceConstants.FIELD_ID).toString()
: "NOT_MIGRATED";
final long count = Long.parseLong(document.get(PersistenceConstants.FIELD_COUNT).toString());
@@ -123,81 +145,59 @@ public Source generateNamespaceCountReport
list.add(entry);
return list;
})
- .map(SearchNamespaceReportResult::new);
+ .map(SearchNamespaceReportResult::new);
}
@Override
- public Source count(final PolicyRestrictedSearchAggregation policyRestrictedSearchAggregation) {
- checkNotNull(policyRestrictedSearchAggregation, "policy restricted aggregation");
+ public Source count(final Query query,
+ @Nullable final List authorizationSubjectIds) {
- final Source source = policyRestrictedSearchAggregation.execute(collection, maxQueryTime);
-
- return source.map(doc -> doc.get(PersistenceConstants.COUNT_RESULT_NAME))
- .map(countResult -> (Number) countResult)
- .map(Number::longValue) // use Number.longValue() to support both Integer and Long values
- .orElse(Source.single(0L))
- .mapError(handleMongoExecutionTimeExceededException())
- .log("count");
- }
-
- @Override
- public Source, NotUsed> findAll(final PolicyRestrictedSearchAggregation aggregation) {
- checkNotNull(aggregation, "aggregation");
-
- final Source source = aggregation.execute(collection, maxQueryTime);
-
- return source.map(doc -> doc.getString(PersistenceConstants.FIELD_ID))
- .fold(new ArrayList(), (list, id) -> {
- list.add(id);
- return list;
- })
- .map(resultsPlus0ne -> toResultList(resultsPlus0ne, aggregation.getSkip(), aggregation.getLimit()))
- .mapError(handleMongoExecutionTimeExceededException())
- .log("findAll");
- }
-
- @Override
- public Source count(final Query query) {
checkNotNull(query, "query");
- final BsonDocument queryFilter = getMongoFilter(query);
+ final BsonDocument queryFilter = getMongoFilter(query, authorizationSubjectIds);
log.debug("count with query filter <{}>.", queryFilter);
- final Bson filter = and(filterNotDeleted(), queryFilter);
-
final CountOptions countOptions = new CountOptions()
.skip(query.getSkip())
.limit(query.getLimit())
.maxTime(maxQueryTime.getSeconds(), TimeUnit.SECONDS);
- return Source.fromPublisher(collection.count(filter, countOptions))
+ return Source.fromPublisher(collection.count(queryFilter, countOptions))
.mapError(handleMongoExecutionTimeExceededException())
.log("count");
}
@Override
- public Source, NotUsed> findAll(final Query query) {
+ public Source sudoCount(final Query query) {
+ return count(query, null);
+ }
+
+ @Override
+ public Source, NotUsed> findAll(final Query query,
+ @Nullable final List authorizationSubjectIds,
+ @Nullable final Set namespaces) {
+
checkNotNull(query, "query");
- final BsonDocument queryFilter = getMongoFilter(query);
+ final BsonDocument queryFilter = getMongoFilter(query, authorizationSubjectIds);
if (log.isDebugEnabled()) {
log.debug("findAll with query filter <{}>.", queryFilter);
}
- final Bson filter = and(filterNotDeleted(), queryFilter);
- final Optional sortOptions = Optional.of(getMongoSort(query));
+ final Bson sortOptions = getMongoSort(query);
final int limit = query.getLimit();
final int skip = query.getSkip();
final Bson projection = new Document(PersistenceConstants.FIELD_ID, 1);
- return Source.fromPublisher(collection.find(filter, Document.class)
- .sort(sortOptions.orElse(null))
- .limit(limit + 1)
- .skip(skip)
- .projection(projection)
- .maxTime(maxQueryTime.getSeconds(), TimeUnit.SECONDS)
- )
+ return Source.fromPublisher(
+ collection.find(queryFilter, Document.class)
+ .hint(hints.getHint(namespaces).orElse(null))
+ .sort(sortOptions)
+ .limit(limit + 1)
+ .skip(skip)
+ .projection(projection)
+ .maxTime(maxQueryTime.getSeconds(), TimeUnit.SECONDS))
.map(doc -> doc.getString(PersistenceConstants.FIELD_ID))
.fold(new ArrayList(), (list, id) -> {
list.add(id);
@@ -226,9 +226,14 @@ private ResultList toResultList(final List resultsPlus0ne, final
return pagedResultList;
}
- private static BsonDocument getMongoFilter(final Query query) {
- return org.eclipse.ditto.services.utils.persistence.mongo.BsonUtil.toBsonDocument(
- CreateBsonVisitor.apply(query.getCriteria()));
+ private static BsonDocument getMongoFilter(final Query query,
+ @Nullable final List authorizationSubjectIds) {
+
+ if (authorizationSubjectIds != null) {
+ return BsonUtil.toBsonDocument(CreateBsonVisitor.apply(query.getCriteria(), authorizationSubjectIds));
+ } else {
+ return BsonUtil.toBsonDocument(CreateBsonVisitor.sudoApply(query.getCriteria()));
+ }
}
private static Bson getMongoSort(final Query query) {
@@ -236,7 +241,7 @@ private static Bson getMongoSort(final Query query) {
return mongoQuery.getSortOptionsAsBson();
}
- private static PartialFunction handleMongoExecutionTimeExceededException() {
+ private PartialFunction handleMongoExecutionTimeExceededException() {
return new PFBuilder()
.match(Throwable.class, error ->
error instanceof MongoExecutionTimeoutException
@@ -245,5 +250,4 @@ private static PartialFunction handleMongoExecutionTimeExc
)
.build();
}
-
}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/PolicyRestrictedSearchAggregation.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/PolicyRestrictedSearchAggregation.java
deleted file mode 100644
index 30e25dd4cb..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/PolicyRestrictedSearchAggregation.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read;
-
-import java.time.Duration;
-import java.util.List;
-
-import org.bson.Document;
-import org.bson.conversions.Bson;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-
-import com.mongodb.reactivestreams.client.MongoCollection;
-
-import akka.NotUsed;
-import akka.stream.javadsl.Source;
-
-/**
- * Defines an aggregation.
- */
-public interface PolicyRestrictedSearchAggregation {
-
- /**
- * Returns the aggregation pipeline consisting of the ordered stages used for the aggregation operation.
- *
- * @return a list of aggregation stages - the aggregation pipeline
- */
- List getAggregationPipeline();
-
- /**
- * Returns the used skip value for this aggregation.
- * @return the skip value
- */
- int getSkip();
-
- /**
- * Returns the used limit value for this aggregation.
- *
- * @return the limit value
- */
- int getLimit();
-
- /**
- * Returns the search criteria.
- *
- * @return a {@code Criteria} object.
- */
- Criteria getCriteria();
-
- /**
- * Executes this aggregation on the specified collection.
- *
- * @param collection the MongoDB collection to be aggregated.
- * @param maxTime maximum time the query is allowed to execute on MongoDB.
- * @throws NullPointerException if {@code collection} is {@code null}.
- */
- Source execute(MongoCollection collection, final Duration maxTime);
-
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/ThingsSearchPersistence.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/ThingsSearchPersistence.java
index 0d41d2fc14..a49d1f3e9f 100644
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/ThingsSearchPersistence.java
+++ b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/ThingsSearchPersistence.java
@@ -12,15 +12,20 @@
*/
package org.eclipse.ditto.services.thingsearch.persistence.read;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.CompletionStage;
+import javax.annotation.Nullable;
+
import org.eclipse.ditto.model.query.Query;
import org.eclipse.ditto.services.models.thingsearch.SearchNamespaceReportResult;
-import org.eclipse.ditto.services.thingsearch.common.model.ResultList;
import akka.NotUsed;
import akka.stream.javadsl.Source;
+import org.eclipse.ditto.services.thingsearch.common.model.ResultList;
+
/**
* Interface for thing operations on the persistence used within the search service.
*/
@@ -34,46 +39,53 @@ public interface ThingsSearchPersistence {
CompletionStage initializeIndices();
/**
- * Returns the count of documents found by the given {@code policyRestrictedSearchAggregation}.
+ * Generate a report of things per Namespace.
*
- * @param policyRestrictedSearchAggregation the policyRestrictedSearchAggregation for matching.
- * @return an {@link Source} which emits the count.
- * @throws NullPointerException if {@code policyRestrictedSearchAggregation} is {@code null}.
+ * @return Source that emits the report.
*/
- Source count(PolicyRestrictedSearchAggregation policyRestrictedSearchAggregation);
+ Source generateNamespaceCountReport();
/**
- * Returns the IDs for all found documents.
+ * Returns the count of documents found by the given {@code query}.
*
- * @param policyRestrictedSearchAggregation the policyRestrictedSearchAggregation for matching.
- * @return an {@link Source} which emits the IDs.
- * @throws NullPointerException if {@code policyRestrictedSearchAggregation} is {@code null}.
+ * @param query the query for matching.
+ * @param authorizationSubjectIds authorization subject IDs.
+ * @return an {@link Source} which emits the count.
+ * @throws NullPointerException if {@code query} is {@code null}.
*/
- Source, NotUsed> findAll(PolicyRestrictedSearchAggregation policyRestrictedSearchAggregation);
+ Source count(Query query, List authorizationSubjectIds);
/**
- * Generate a report of things per Namespace.
+ * Returns the count of documents found by the given {@code query} regardless of visibility.
*
- * @return Source that emits the report.
+ * @param query the query for matching.
+ * @return an {@link Source} which emits the count.
+ * @throws NullPointerException if {@code query} is {@code null}.
*/
- Source generateNamespaceCountReport();
+ Source sudoCount(Query query);
/**
- * Returns the count of documents found by the given {@code query}.
+ * Returns the IDs for all found documents.
*
* @param query the query for matching.
- * @return an {@link Source} which emits the count.
+ * @param authorizationSubjectIds authorization subject IDs.
+ * @param namespaces namespaces to execute searches in, or null to search in all namespaces.
+ * @return an {@link Source} which emits the IDs.
* @throws NullPointerException if {@code query} is {@code null}.
*/
- Source count(Query query);
+ Source, NotUsed> findAll(Query query, List authorizationSubjectIds,
+ @Nullable Set namespaces);
/**
* Returns the IDs for all found documents.
*
* @param query the query for matching.
+ * @param authorizationSubjectIds authorization subject IDs.
* @return an {@link Source} which emits the IDs.
* @throws NullPointerException if {@code query} is {@code null}.
*/
- Source, NotUsed> findAll(Query query);
+ default Source, NotUsed> findAll(final Query query, final List authorizationSubjectIds) {
+ return findAll(query, authorizationSubjectIds, null);
+ }
}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ContainsAllRequiredResourcesVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ContainsAllRequiredResourcesVisitor.java
deleted file mode 100644
index 4fe9106743..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ContainsAllRequiredResourcesVisitor.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
-
-import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import org.bson.Document;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
-import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
-import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.services.thingsearch.persistence.PersistenceConstants;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.IsInternalViewVisitor;
-
-/**
- * Tests whether all resources requried to evaluate a search criteria are present.
- */
-public class ContainsAllRequiredResourcesVisitor implements CriteriaVisitor> {
-
- private static ContainsAllRequiredResourcesVisitor instance;
-
- private ContainsAllRequiredResourcesVisitor() {
- // only internally instantiable
- }
-
- /**
- * Gets the singleton instance of this {@link ContainsAllRequiredResourcesVisitor}.
- *
- * @return the singleton instance.
- */
- public static ContainsAllRequiredResourcesVisitor getInstance() {
- if (null == instance) {
- instance = new ContainsAllRequiredResourcesVisitor();
- }
- return instance;
- }
-
- /**
- * Tests whether a thing in the search result has all required resources.
- *
- * @param criteria The search criteria.
- * @param thingResult The thing in the search result combined from all visible fields.
- * @return Whether all fields required to evaluate the criteria are present.
- */
- public static boolean apply(final Criteria criteria, final Document thingResult) {
- return criteria.accept(getInstance()).test(thingResult);
- }
-
- @Override
- public Predicate visitAnd(final Stream> conjuncts) {
- return thingResult -> conjuncts.allMatch(child -> child.test(thingResult));
- }
-
- @Override
- public Predicate visitAny() {
- return thingResult -> true;
- }
-
- @Override
- public Predicate visitExists(final ExistsFieldExpression fieldExpression) {
- return thingResult -> {
- final Predicate predicate = fieldExpression.accept(new IsInternalViewVisitor());
- final List> internalList = thingResult.get(PersistenceConstants.FIELD_INTERNAL, List.class);
- return internalList.stream()
- .anyMatch(element -> element instanceof Document && predicate.test((Document) element));
- };
- }
-
- @Override
- public Predicate visitField(final FilterFieldExpression fieldExpression,
- final org.eclipse.ditto.model.query.criteria.Predicate predicate) {
- return thingResult -> {
- final java.util.function.Predicate javaPredicate =
- fieldExpression.accept(new IsInternalViewVisitor());
- final List> internalList = thingResult.get(PersistenceConstants.FIELD_INTERNAL, List.class);
- return internalList.stream()
- .anyMatch(element -> element instanceof Document && javaPredicate.test((Document) element));
- };
- }
-
- @Override
- public Predicate visitNor(final Stream> negativeDisjoints) {
- return thingResult -> negativeDisjoints.anyMatch(child -> child.test(thingResult));
- }
-
- @Override
- public Predicate visitOr(final Stream> disjoints) {
- return thingResult -> disjoints.anyMatch(child -> child.test(thingResult));
- }
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateBsonVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateBsonVisitor.java
index 1f5b87d1fa..4a128587f0 100644
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateBsonVisitor.java
+++ b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateBsonVisitor.java
@@ -12,9 +12,15 @@
*/
package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
+import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull;
+
+import java.util.List;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.annotation.Nullable;
+
import org.bson.BsonDocument;
import org.bson.conversions.Bson;
import org.eclipse.ditto.model.query.criteria.Criteria;
@@ -22,48 +28,68 @@
import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetExistsBsonVisitor;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetFilterBsonVisitor;
import com.mongodb.client.model.Filters;
+import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.AbstractFieldBsonCreator;
+import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetExistsBsonVisitor;
+import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetFilterBsonVisitor;
+
/**
- * Creates the Bson object used for the PolicyRestrictedSearchAggregation.
+ * Creates the Bson object used for querying.
*/
public class CreateBsonVisitor implements CriteriaVisitor {
- private CreateBsonVisitor() {
- // only internally instantiable
+ @Nullable
+ private final List authorizationSubjectIds;
+
+ private CreateBsonVisitor(@Nullable final List authorizationSubjectIds) {
+ this.authorizationSubjectIds = authorizationSubjectIds;
}
/**
- * Creates the Bson object used for the PolicyRestrictedSearchAggregation.
+ * Creates the Bson object used for querying with no restriction of visibility.
*
* @param criteria the criteria to create Bson for.
* @return the Bson object
*/
- public static Bson apply(final Criteria criteria) {
- return criteria.accept(new CreateBsonVisitor());
+ public static Bson sudoApply(final Criteria criteria) {
+ return criteria.accept(new CreateBsonVisitor(null));
}
- @Override
- public Bson visitAnd(final Stream conjuncts) {
- return Filters.and(conjuncts.collect(Collectors.toList()));
- }
+ /**
+ * Creates the Bson object used for querying.
+ *
+ * @param criteria the criteria to create Bson for.
+ * @param authorizationSubjectIds subject ids with which to restrict visibility, or null to not restrict visibility.
+ * @return the Bson object
+ */
+ public static Bson apply(final Criteria criteria, List authorizationSubjectIds) {
+ checkNotNull(criteria, "criteria");
+ checkNotNull(authorizationSubjectIds, "authorizationSubjectIds");
+ final Bson baseFilter = criteria.accept(new CreateBsonVisitor(authorizationSubjectIds));
+ final Bson globalReadableFilter = AbstractFieldBsonCreator.getGlobalReadBson(authorizationSubjectIds);
- @Override
- public Bson visitAny() {
- return new BsonDocument();
+ // Put both per-attribute-filter and global-read filter in the query so that:
+ // 1. Purely negated queries do not return results invisible to the authorization subjects, and
+ // 2. MongoDB may choose to scan the global-read index when the key-value filter does not discriminate enough.
+ return Filters.and(baseFilter, globalReadableFilter);
}
@Override
public Bson visitExists(final ExistsFieldExpression fieldExpression) {
- return GetExistsBsonVisitor.apply(fieldExpression);
+ return GetExistsBsonVisitor.apply(fieldExpression, authorizationSubjectIds);
}
@Override
public Bson visitField(final FilterFieldExpression fieldExpression, final Predicate predicate) {
- return GetFilterBsonVisitor.apply(fieldExpression, predicate.accept(CreateBsonPredicateVisitor.getInstance()));
+ final Function predicateCreator = predicate.accept(CreateBsonPredicateVisitor.getInstance());
+ return GetFilterBsonVisitor.apply(fieldExpression, predicateCreator, authorizationSubjectIds);
+ }
+
+ @Override
+ public Bson visitAny() {
+ return new BsonDocument();
}
@Override
@@ -75,4 +101,9 @@ public Bson visitNor(final Stream negativeDisjoints) {
public Bson visitOr(final Stream disjoints) {
return Filters.or(disjoints.collect(Collectors.toList()));
}
+
+ @Override
+ public Bson visitAnd(final Stream conjuncts) {
+ return Filters.and(conjuncts.collect(Collectors.toList()));
+ }
}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreatePolicyRestrictionBsonVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreatePolicyRestrictionBsonVisitor.java
deleted file mode 100644
index 46559226b4..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreatePolicyRestrictionBsonVisitor.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.bson.BsonDocument;
-import org.bson.conversions.Bson;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-import org.eclipse.ditto.model.query.criteria.Predicate;
-import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
-import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
-import org.eclipse.ditto.model.query.expression.FieldExpression;
-import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.model.query.expression.PolicyRestrictedFieldExpression;
-import org.eclipse.ditto.services.thingsearch.persistence.PersistenceConstants;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetPolicyRestrictionBsonVisitor;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetUnwoundExistsFilterBsonVisitor;
-
-import com.mongodb.client.model.Filters;
-
-/**
- * Builds the BSON query including "granted" and "revoked" fields based on the passed {@code
- * authorizationSubjectsPredicateFunction} which is invoked after the "policiesBasedSearchIndex" {@code granted} and
- * {@code revoked} fields were "joined" in the aggregation pipeline.
- */
-public class CreatePolicyRestrictionBsonVisitor implements CriteriaVisitor> {
-
- private final Bson grantedBson;
- private final Bson notRevokedBson;
-
- /**
- * Creates a visitor to create policy-restriction Bson objects.
- *
- * @param authorizationSubjectsPredicate the predicate returning the "subject ids" of the search request.
- */
- private CreatePolicyRestrictionBsonVisitor(final Predicate authorizationSubjectsPredicate) {
- grantedBson = CreateBsonPredicateVisitor.apply(authorizationSubjectsPredicate, PersistenceConstants.FIELD_GRANTS_GRANTED);
- notRevokedBson =
- Filters.not(CreateBsonPredicateVisitor.apply(authorizationSubjectsPredicate, PersistenceConstants.FIELD_GRANTS_REVOKED));
- }
-
- /**
- * Builds the BSON query including "granted" and "revoked" fields based on the passed {@code
- * authorizationSubjectsPredicateFunction} which is invoked after the "policiesBasedSearchIndex" {@code granted} and
- * {@code revoked} fields were "joined" in the aggregation pipeline.
- *
- * @param criteria the criteria to create policy-restricted bson for.
- * @param authorizationSubjectsPredicate the predicate returning the "subject ids" of the search request.
- * @return the BSON to use in the aggregation pipeline after joining the "policiesBasedSearchIndex" entries.
- */
- public static Optional apply(final Criteria criteria, final Predicate authorizationSubjectsPredicate) {
- return criteria.accept(new CreatePolicyRestrictionBsonVisitor(authorizationSubjectsPredicate));
- }
-
- @Override
- public Optional visitAnd(final Stream> conjuncts) {
- return visitAndOrNor(conjuncts);
- }
-
- @Override
- public Optional visitAny() {
- return Optional.of(new BsonDocument());
- }
-
- @Override
- public Optional visitExists(final ExistsFieldExpression fieldExpression) {
- return visitFieldExpression(fieldExpression);
- }
-
- @Override
- public Optional visitField(final FilterFieldExpression fieldExpression, final Predicate predicate) {
- return visitFieldExpression(fieldExpression);
- }
-
- @Override
- public Optional visitNor(final Stream> negativeDisjoints) {
- return visitAndOrNor(negativeDisjoints);
- }
-
- @Override
- public Optional visitOr(final Stream> disjoints) {
- return visitAndOrNor(disjoints);
- }
-
- private Optional visitAndOrNor(final Stream> components) {
- final List filters = components
- .flatMap(filter -> filter.map(Stream::of).orElse(Stream.empty()))
- .collect(Collectors.toList());
- if (filters.isEmpty()) {
- return Optional.empty();
- } else {
- return Optional.of(Filters.or(filters));
- }
-
- }
-
- private Optional visitFieldExpression(final FieldExpression fieldExpression) {
- return onPolicyRestrictedFieldExpression(fieldExpression, Optional.empty(), policyRestrictedFieldExpression -> {
- final Bson existsExpression = GetUnwoundExistsFilterBsonVisitor.apply(policyRestrictedFieldExpression);
- final Bson policyRestrictionBson = GetPolicyRestrictionBsonVisitor.apply(policyRestrictedFieldExpression);
- final Bson filter = Filters.and(existsExpression, policyRestrictionBson, grantedBson, notRevokedBson);
- return Optional.of(filter);
- });
- }
-
- private T onPolicyRestrictedFieldExpression(final Object input, final T defaultOutput,
- final Function processor) {
- if (input instanceof PolicyRestrictedFieldExpression) {
- return processor.apply((PolicyRestrictedFieldExpression) input);
- } else {
- return defaultOutput;
- }
- }
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateUnwoundBsonVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateUnwoundBsonVisitor.java
deleted file mode 100644
index c8f83a0aef..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/CreateUnwoundBsonVisitor.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.bson.conversions.Bson;
-import org.eclipse.ditto.model.query.criteria.Criteria;
-import org.eclipse.ditto.model.query.criteria.Predicate;
-import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
-import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
-import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.CreateUnwoundBsonFieldVisitor;
-
-import com.mongodb.client.model.Filters;
-
-/**
- * Creates the Bson object to filter out irrelevant fields.
- */
-public class CreateUnwoundBsonVisitor implements CriteriaVisitor>> {
-
- private static CreateUnwoundBsonVisitor instance;
-
- private CreateUnwoundBsonVisitor() {
- // only internally instantiable
- }
-
- /**
- * Gets the singleton instance of this {@link CreateUnwoundBsonVisitor}.
- *
- * @return the singleton instance.
- */
- public static CreateUnwoundBsonVisitor getInstance() {
- if (null == instance) {
- instance = new CreateUnwoundBsonVisitor();
- }
- return instance;
- }
-
- /**
- * Creates unwound Bson, starting in the positive state.
- *
- * @param criteria The criteria to create unwound Bson for.
- * @return The generated Bson.
- */
- public static Optional apply(final Criteria criteria) {
- return criteria.accept(getInstance()).apply(true);
- }
-
- @Override
- public Function> visitAnd(final Stream>> conjuncts) {
- return buildCompositeBsonCreator(conjuncts, Function.identity(), Filters::or, Filters::and);
- }
-
- @Override
- public Function> visitAny() {
- return isPositive -> Optional.empty();
- }
-
- @Override
- public Function> visitExists(final ExistsFieldExpression fieldExpression) {
- return isPositive -> fieldExpression.accept(new CreateUnwoundBsonFieldVisitor(null));
- }
-
- @Override
- public Function> visitField(final FilterFieldExpression fieldExpression, final Predicate predicate) {
- return isPositive -> fieldExpression.accept(new CreateUnwoundBsonFieldVisitor(predicate));
- }
-
- @Override
- public Function> visitNor(final Stream>> negativeDisjoints) {
- return buildCompositeBsonCreator(negativeDisjoints, isPostive -> !isPostive,
- children -> Filters.nor(Filters.and(children)),
- children -> Filters.nor(Filters.or(children)));
- }
-
- @Override
- public Function> visitOr(final Stream>> disjoints) {
- return buildCompositeBsonCreator(disjoints, Function.identity(), Filters::or, Filters::and);
- }
-
- // common template of And, Or, Nor
- private Function> buildCompositeBsonCreator(
- final Stream>> childFunctions,
- final Function areChildrenPositive,
- final Function, Bson> positiveFilter, final Function, Bson> negativeFilter) {
-
- return isPositive -> {
-
- final Boolean childPositivity = areChildrenPositive.apply(isPositive);
- final List childBsons = childFunctions
- .flatMap(childFunction -> childFunction.apply(childPositivity)
- .map(Stream::of)
- .orElse(Stream.empty()))
- .collect(Collectors.toList());
-
- if (childBsons.isEmpty()) {
- return Optional.empty();
- } else {
- final Function, Bson> filter = isPositive ? positiveFilter : negativeFilter;
- return Optional.of(filter.apply(childBsons));
- }
- };
- }
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/IsPolicyLookupNeededVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/IsPolicyLookupNeededVisitor.java
deleted file mode 100644
index 98fc449626..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/IsPolicyLookupNeededVisitor.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
-
-import java.util.stream.Stream;
-
-import org.eclipse.ditto.model.query.criteria.Predicate;
-import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
-import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
-import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.model.query.expression.PolicyRestrictedFieldExpression;
-
-/**
- * Check whether a filter criteria requires policy lookup.
- */
-public final class IsPolicyLookupNeededVisitor implements CriteriaVisitor {
-
- @Override
- public Boolean visitAnd(final Stream conjuncts) {
- return conjuncts.anyMatch(x -> x);
- }
-
- @Override
- public Boolean visitAny() {
- return false;
- }
-
- @Override
- public Boolean visitExists(final ExistsFieldExpression fieldExpression) {
- return fieldExpression instanceof PolicyRestrictedFieldExpression;
- }
-
- @Override
- public Boolean visitField(final FilterFieldExpression fieldExpression, final Predicate predicate) {
- return fieldExpression instanceof PolicyRestrictedFieldExpression;
- }
-
- @Override
- public Boolean visitNor(final Stream negativeDisjoints) {
- return negativeDisjoints.anyMatch(x -> x);
- }
-
- @Override
- public Boolean visitOr(final Stream disjoints) {
- return disjoints.anyMatch(x -> x);
- }
-}
diff --git a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ResourceNamesVisitor.java b/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ResourceNamesVisitor.java
deleted file mode 100644
index bea1bd8ada..0000000000
--- a/services/thingsearch/persistence/src/main/java/org/eclipse/ditto/services/thingsearch/persistence/read/criteria/visitors/ResourceNamesVisitor.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2017 Contributors to the Eclipse Foundation
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.eclipse.ditto.services.thingsearch.persistence.read.criteria.visitors;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.stream.Stream;
-
-import org.eclipse.ditto.model.query.criteria.Predicate;
-import org.eclipse.ditto.model.query.criteria.visitors.CriteriaVisitor;
-import org.eclipse.ditto.model.query.expression.ExistsFieldExpression;
-import org.eclipse.ditto.model.query.expression.FilterFieldExpression;
-import org.eclipse.ditto.services.thingsearch.persistence.read.expression.visitors.GetFieldIdentifierVisitor;
-
-/**
- * Collects names of resources.
- */
-public class ResourceNamesVisitor implements CriteriaVisitor> {
-
- private ResourceNamesVisitor() {
- // only internally instantiable
- }
-
- @Override
- public Set visitAnd(final Stream> conjuncts) {
- return union(conjuncts);
- }
-
- @Override
- public Set visitAny() {
- return Collections.emptySet();
- }
-
- @Override
- public Set visitExists(final ExistsFieldExpression fieldExpression) {
- return Collections.singleton(GetFieldIdentifierVisitor.apply(fieldExpression));
- }
-
- @Override
- public Set visitField(final FilterFieldExpression fieldExpression, final Predicate predicate) {
- return Collections.singleton(GetFieldIdentifierVisitor.apply(fieldExpression));
- }
-
- @Override
- public Set visitNor(final Stream> negativeDisjoints) {
- return union(negativeDisjoints);
- }
-
- @Override
- public Set visitOr(final Stream> disjoints) {
- return union(disjoints);
- }
-
- private Set union(final Stream