Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, without warranties or
* conditions of any kind, EITHER EXPRESS OR IMPLIED. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.vmware.xenon.services.common;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import com.esotericsoftware.kryo.serializers.VersionFieldSerializer.Since;
import com.vmware.xenon.common.ServiceDocument;
import com.vmware.xenon.common.ServiceDocumentDescription.TypeName;
import com.vmware.xenon.common.ServiceDocumentQueryResult;
import com.vmware.xenon.common.TaskState;
import com.vmware.xenon.common.Utils;
import com.vmware.xenon.common.serialization.ReleaseConstants;
import com.vmware.xenon.services.common.QueryTask.QuerySpecification.QueryOption;
import com.vmware.xenon.services.common.QueryTask.QuerySpecification.SortOrder;
import com.vmware.xenon.services.common.QueryTask.QueryTerm.MatchType;
public class QueryTask extends ServiceDocument {
public static final String KIND = Utils.buildKind(QueryTask.class);
/**
* Default precision step used for indexing long and double values. This is also the default value used for
* {@link NumericRange#precisionStep}.
*/
public static final int DEFAULT_PRECISION_STEP = 16;
public static class QuerySpecification {
public static final String FIELD_NAME_CHARACTER = ".";
public static final String FIELD_NAME_REGEXP = "\\" + FIELD_NAME_CHARACTER;
public static final String COLLECTION_FIELD_SUFFIX = "item";
/**
* Infrastructure use only (not serialized)
*/
public static class QueryRuntimeContext {
public transient Object nativeQuery;
public transient Object nativePage;
public transient Object nativeSearcher;
public transient Object nativeSort;
public transient QueryFilter filter;
/**
* Set of document links that should be considered in query execution. Any document not
* in the list must be discarded. This is an implementation specific hint
*/
public transient Set documentLinkWhiteList;
/**
* The subject link of the user that created the query task.
*/
public transient String subjectLink;
/**
* Kind scope for the query. If the query does not contain one or more kind clauses, the
* field will be null;
*/
public Set kindScope;
}
public enum QueryOption {
/**
* Query results are updated in real time, by using {@code QueryFilter} instance on the index.
* Any update that satisfies the query filter will cause the results to be updated and a self
* PATCH to be sent on the service.
*/
CONTINUOUS,
/**
* Query results will return the number of documents that satisfy the query and populate the
* the {@link ServiceDocumentQueryResult#documentCount} field. The results will not contain
* links or documents
*/
COUNT,
/**
* The query will execute on the current view of the index, potentially missing recent updates.
* This improves performance but does not guarantee latest results.
*/
DO_NOT_REFRESH,
/**
* The query will return the top N results, with N specified through the resultLimit field.
* The query results will be available in the results field and nextPageLink will be null.
*/
TOP_RESULTS,
/**
* Query results will include the state documents in the {@link ServiceDocumentQueryResult#documents}
* collection
*/
EXPAND_CONTENT,
/**
* Query results include the values for selected fields included in
* {@link QuerySpecification#selectTerms}. The fields are then available through
* the state documents in the {@link ServiceDocumentQueryResult#documents}
* collection
*/
EXPAND_SELECTED_FIELDS,
/**
* Query results will be in binary form. This option should only be set on local query tasks,
* with the client co-located (same service host) as the query task. This should not
* be used along with EXPAND_CONTENT / EXPAND_BUILTIN_CONTENT_ONLY / OWNER_SELECTION.
*/
EXPAND_BINARY_CONTENT,
/**
* Infrastructure use only. Modifier option on EXPAND_CONTENT:
* Selects and expands only the the built-in document fields
* See {@link ServiceDocument}
*/
EXPAND_BUILTIN_CONTENT_ONLY,
/**
* Query execution will issue GET requests to the document links in each document in
* the results. The content will be placed in the
* {@code ServiceDocumentQueryResult#selectedDocuments} map.
* This option must be combined with SELECT_LINKS
*/
EXPAND_LINKS,
/**
* The query will execute over all document versions, not just the latest per self link. Each
* document self link will be annotated with the version. Document versions marked
* deleted will also be included
*/
INCLUDE_ALL_VERSIONS,
/**
* Query results will include document versions marked deleted
*/
INCLUDE_DELETED,
/**
* Query results will be sorted by the specified sort field
*/
SORT,
/**
* Infrastructure use only. Query originated from a query task service
*/
TASK,
/**
* Broadcast the query to each node, using the local query task factory.
* It then merges results from each node. See related option @{code QueryOption.OWNER_SELECTION}
*/
BROADCAST,
/**
* Ensures read after write consistency for query results.
* This option requires that the membership quorum be set to a majority of the nodes in the
* node group and all services involved in the query needs to have ServiceOption.OWNER_SELECTION
* enabled
*/
READ_AFTER_WRITE_CONSISTENCY,
/**
* Filters query results based on the document owner ID.
* If the owner ID of the document does not match the ID of the host executing the query,
* the document is removed from the result
*/
OWNER_SELECTION,
/**
* Query results include the values for all link fields included in
* {@link QuerySpecification#linkTerms}. The links are then available through
* {@link ServiceDocumentQueryResult#selectedLinks} and
* {@link ServiceDocumentQueryResult#selectedLinksPerDocument}
*/
SELECT_LINKS,
/**
* Groups results using the {@link QuerySpecification::groupByTerms}
*/
GROUP_BY,
/**
* Query will return latest versions of documents before {@link QuerySpecification#timeSnapshotBoundaryMicros}
*/
TIME_SNAPSHOT,
/**
* Query pages will be deleted immediately after first access instead of at query task
* expiration time, and any index service resources backing the query will be deleted
* after the last page is accessed.
*
* Note this option disables sharing of index service resources with other queries and
* may increase overall resource usage.
*/
SINGLE_USE,
/**
* Query target documents have {@code DocumentIndexingOption#INDEX_METADATA} enabled,
* and the query contents can be rewritten to take advantage of the additional indexed
* metadata.
*/
INDEXED_METADATA,
/**
* Query result will NOT create previous pages.
* When this option is used with BROADCAST option, it will also NOT create previous page
* for broadcast result({@link BroadcastQueryPageService}.
*/
FORWARD_ONLY,
}
public enum SortOrder {
ASC, DESC
}
/*
* Query definition
*/
public Query query = new Query();
/**
* Property names of fields annotated with PropertyUsageOption.LINK. Used in combination with
* {@code QueryOption#SELECT_LINKS}
*/
public List linkTerms;
/**
* Property names of fields to select. Used in combination with
* {@code QueryOption#SELECT_FIELDS}
*/
@Since(ReleaseConstants.RELEASE_VERSION_1_4_2)
public List selectTerms;
/**
* Property name to use for primary sort. Used in combination with {@code QueryOption#SORT}
*/
public QueryTerm sortTerm;
/**
* Property name to use for group sort. Used in combination with {@code QueryOption#GROUP_BY}
*/
public QueryTerm groupSortTerm;
/**
* Property name to use for additional sort. Used in combination with {@code QueryOption#SORT}
*/
@Since(ReleaseConstants.RELEASE_VERSION_1_3_1)
public List additionalSortTerms;
/**
* Property name to use for additional group sort. Used in combination with {@code QueryOption#GROUP_BY}
*/
@Since(ReleaseConstants.RELEASE_VERSION_1_3_1)
public List additionalGroupSortTerms;
/**
* Property name to use for grouping. Used in combination with {@code QueryOption#GROUP_BY}
*/
public QueryTerm groupByTerm;
/**
* Primary sort order. Used in combination with {@code QueryOption#SORT}
*/
public SortOrder sortOrder;
/**
* Group sort order. Used in combination with {@code QueryOption#GROUP_BY}
*/
public SortOrder groupSortOrder;
/**
* Used for query results pagination. When specified,
* the query task documentLinks and documents will remain empty, but when results are available
* the nextPageLink field will be set. A client can then issue a GET request on the nextPageLink
* to get the first page of results. If additional results are available, each result page will
* have its nextPageLink set.
*/
public Integer resultLimit;
/**
* Used for grouped result pagination, limiting the number of entries in
* {@link ServiceDocumentQueryResult#nextPageLinksPerGroup}
*/
public Integer groupResultLimit;
/**
* Skip number of documents.
* General usage would be combined with TOP_RESULTS option with sorting term specified, but not limited to.
* When used with resultLimit, documents on the first result page start from the one after skipping N offset documents.
*/
@Since(ReleaseConstants.RELEASE_VERSION_1_5_2)
public Integer offset;
/**
* The query is retried until the result count matches the
* specified value or the query expires.
*/
public Long expectedResultCount;
/**
* A set of options that determine query behavior
*/
public EnumSet options = EnumSet.noneOf(QueryOption.class);
/**
* Infrastructure use only
*/
public transient QueryRuntimeContext context = new QueryRuntimeContext();
/**
* Used with {@link QueryOption#TIME_SNAPSHOT}
*/
@Since(ReleaseConstants.RELEASE_VERSION_1_3_6)
public Long timeSnapshotBoundaryMicros;
public static String buildCompositeFieldName(String... fieldNames) {
StringBuilder sb = new StringBuilder();
for (String s : fieldNames) {
if (s == null) {
continue;
}
sb.append(s).append(FIELD_NAME_CHARACTER);
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
public static String buildCollectionItemName(String fieldName) {
return fieldName + FIELD_NAME_CHARACTER + COLLECTION_FIELD_SUFFIX;
}
public static String buildLinkCollectionItemName(String fieldName, int ordinal) {
return fieldName + FIELD_NAME_CHARACTER
+ COLLECTION_FIELD_SUFFIX + FIELD_NAME_CHARACTER + ordinal;
}
/**
* Convert the given value to a normalized string representation that is used for
* both generating indexed values and query criteria used to match against those
* indexes.
*
* @return A string value that can be used to both index and query, or NULL if the given
*/
public static String toMatchValue(Object value) {
if (value == null) {
return null;
} else if (value instanceof String) {
return (String) value;
} else if (value instanceof Boolean) {
return toMatchValue((boolean) value);
} else if (value instanceof URI) {
return toMatchValue((URI) value);
} else if (value instanceof Enum) {
return toMatchValue((Enum>) value);
} else {
return value.toString();
}
}
public static String toMatchValue(boolean value) {
return value ? "true" : "false";
}
public static String toMatchValue(URI value) {
return value == null ? null : value.toString();
}
public static String toMatchValue(Enum> value) {
return value == null ? null : value.name();
}
public static QueryTask addExpandOption(QueryTask queryTask) {
queryTask.querySpec.options = EnumSet
.of(QueryTask.QuerySpecification.QueryOption.EXPAND_CONTENT);
return queryTask;
}
/**
* Performs shallow copy of this instance to the supplied instance
*/
public void copyTo(QuerySpecification clonedSpec) {
clonedSpec.context.documentLinkWhiteList = this.context.documentLinkWhiteList;
clonedSpec.context.filter = this.context.filter;
clonedSpec.context.kindScope = this.context.kindScope;
clonedSpec.context.nativePage = this.context.nativePage;
clonedSpec.context.nativeQuery = this.context.nativeQuery;
clonedSpec.context.nativeSearcher = this.context.nativeSearcher;
clonedSpec.context.nativeSort = this.context.nativeSort;
clonedSpec.expectedResultCount = this.expectedResultCount;
clonedSpec.linkTerms = this.linkTerms;
clonedSpec.selectTerms = this.selectTerms;
clonedSpec.groupByTerm = this.groupByTerm;
clonedSpec.options = EnumSet.copyOf(this.options);
clonedSpec.query = this.query;
clonedSpec.resultLimit = this.resultLimit;
clonedSpec.sortOrder = this.sortOrder;
clonedSpec.sortTerm = this.sortTerm;
clonedSpec.groupSortTerm = this.groupSortTerm;
clonedSpec.groupSortOrder = this.groupSortOrder;
clonedSpec.timeSnapshotBoundaryMicros = this.timeSnapshotBoundaryMicros;
clonedSpec.offset = this.offset;
}
}
public static class NumericRange> {
public TypeName type;
public T min;
public T max;
public boolean isMinInclusive;
public boolean isMaxInclusive;
public int precisionStep = DEFAULT_PRECISION_STEP;
public static NumericRange createLongRange(Long min, Long max,
boolean isMinInclusive, boolean isMaxInclusive) {
NumericRange nr = new NumericRange();
nr.type = TypeName.LONG;
nr.isMaxInclusive = isMaxInclusive;
nr.isMinInclusive = isMinInclusive;
nr.max = max;
nr.min = min;
return nr;
}
public static NumericRange createDoubleRange(Double min, Double max,
boolean isMinInclusive, boolean isMaxInclusive) {
NumericRange nr = new NumericRange();
nr.type = TypeName.DOUBLE;
nr.isMaxInclusive = isMaxInclusive;
nr.isMinInclusive = isMinInclusive;
nr.max = max;
nr.min = min;
return nr;
}
public void validate() throws IllegalArgumentException {
if (this.max == null && this.min == null) {
throw new IllegalArgumentException("max and min can not both be null");
}
if (this.max != null) {
if (this.min != null && this.max.compareTo(this.min) < 0) {
throw new IllegalArgumentException("max must be greater than min");
}
}
if (this.min != null) {
if (this.max != null && this.min.compareTo(this.max) > 0) {
throw new IllegalArgumentException("max must be greater than min");
}
}
if (this.type == null) {
throw new IllegalArgumentException("type must be specified");
}
}
public static NumericRange> createLessThanRange(Number max) {
if (max instanceof Double) {
return createDoubleRange(Double.MIN_VALUE, (Double) max, true, false);
}
return createLongRange(Long.MIN_VALUE, (Long) max, true, false);
}
public static NumericRange> createLessThanOrEqualRange(Number max) {
if (max instanceof Double) {
return createDoubleRange(Double.MIN_VALUE, (Double) max, true, true);
}
return createLongRange(Long.MIN_VALUE, (Long) max, true, true);
}
public static NumericRange> createGreaterThanRange(Number min) {
if (min instanceof Double) {
return createDoubleRange((Double) min, Double.MAX_VALUE, false, true);
}
return createLongRange((Long) min, Long.MAX_VALUE, false, true);
}
public static NumericRange> createGreaterThanOrEqualRange(Number min) {
if (min instanceof Double) {
return createDoubleRange((Double) min, Double.MAX_VALUE, true, true);
}
return createLongRange((Long) min, Long.MAX_VALUE, true, true);
}
public static NumericRange> createEqualRange(Number num) {
if (num instanceof Double) {
return createDoubleRange((Double) num, (Double) num, true, true);
}
return createLongRange((Long) num, (Long) num, true, true);
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof NumericRange>) {
NumericRange> nObj = (NumericRange>)obj;
if ((this.isMaxInclusive == nObj.isMaxInclusive)
&& (this.isMinInclusive == nObj.isMinInclusive)
&& Objects.equals(this.max, nObj.max)
&& Objects.equals(this.min, nObj.min)
&& Objects.equals(this.precisionStep, nObj.precisionStep)
&& Objects.equals(this.type, nObj.type)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(this.max, this.min, this.precisionStep, this.type);
}
}
public static class QueryTerm {
public enum MatchType {
WILDCARD, TERM, PHRASE, PREFIX
}
public String propertyName;
public TypeName propertyType;
public String matchValue;
public MatchType matchType;
public NumericRange> range;
@Since(ReleaseConstants.RELEASE_VERSION_1_3_1)
public SortOrder sortOrder;
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof QueryTerm) {
QueryTerm qObj = (QueryTerm)obj;
if (Objects.equals(this.propertyName, qObj.propertyName)
&& Objects.equals(this.propertyType, qObj.propertyType)
&& Objects.equals(this.matchType, qObj.matchType)
&& Objects.equals(this.matchValue, qObj.matchValue)
&& Objects.equals(this.range, qObj.range)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(this.propertyName, this.propertyType, this.matchType, this.matchValue, this.range);
}
}
public static class Query {
public enum Occurance {
MUST_OCCUR, MUST_NOT_OCCUR, SHOULD_OCCUR
}
/**
* Builder class for constructing {@linkplain Query Xenon queries}.
*/
public static final class Builder {
private final Query query;
private Builder(Occurance occurance) {
this.query = new Query();
this.query.occurance = occurance;
}
/**
* Constructs a query that {@linkplain Occurance#MUST_OCCUR must occur} in matched documents.
* @return a reference to this object.
*/
public static Builder create() {
return new Builder(Occurance.MUST_OCCUR);
}
/**
* Constructs a query with the given {@linkplain Occurance occurance}.
* @param occurance the occurance.
* @return a reference to this object.
*/
public static Builder create(Occurance occurance) {
return new Builder(occurance);
}
/**
* Add a clause which matches the {@linkplain ServiceDocument#documentKind document kind} of the provided class.
* @param documentClass the service document class.
* @return a reference to this object.
*/
public Builder addKindFieldClause(Class extends ServiceDocument> documentClass) {
return addFieldClause(FIELD_NAME_KIND, Utils.buildKind(documentClass));
}
/**
* Add a clause with the specified occurance which matches the
* {@linkplain ServiceDocument#documentKind document kind} of the provided class.
* @param documentClass the service document class.
* @param occurance the occurance for this clause.
* @return a reference to this object.
*/
public Builder addKindFieldClause(Class extends ServiceDocument> documentClass,
Occurance occurance) {
return addFieldClause(FIELD_NAME_KIND, Utils.buildKind(documentClass), occurance);
}
/**
* Add a clause which matches a collection item.
* @param collectionFieldName the collection field name.
* @param itemName the item name in the collection to match.
* @return a reference to this object.
*/
public Builder addCollectionItemClause(String collectionFieldName, String itemName) {
return addFieldClause(
QuerySpecification.buildCollectionItemName(collectionFieldName),
itemName);
}
/**
* Add a clause with the specified occurance which matches a collection item.
* @param collectionFieldName the collection field name.
* @param itemName the item name in the collection to match.
* @param occurance the occurance for this clause.
* @return a reference to this object.
*/
public Builder addCollectionItemClause(String collectionFieldName, String itemName,
Occurance occurance) {
return addFieldClause(
QuerySpecification.buildCollectionItemName(collectionFieldName),
itemName,
occurance);
}
/**
* Add a clause which matches a property with at least one of several specified
* values (analogous to a SQL "IN" statement).
* @param fieldName the field name.
* @param itemNames the item names in the collection to match.
* @return a reference to this object.
*/
public Builder addInClause(String fieldName, Collection itemNames) {
return addInClause(fieldName, itemNames, Occurance.MUST_OCCUR);
}
/**
* Add a clause with the given occurance which matches a property with at least one of several specified
* values (analogous to a SQL "IN" or "NOT IN" statements).
* @param fieldName the field name.
* @param itemNames the item names in the collection to match.
* @param occurance the occurance for this clause.
* @return a reference to this object.
*/
public Builder addInClause(String fieldName, Collection itemNames,
Occurance occurance) {
if (itemNames.size() == 1) {
return addFieldClause(
fieldName,
itemNames.iterator().next(),
occurance);
}
Query.Builder inClause = Query.Builder.create(occurance);
for (String itemName : itemNames) {
inClause.addFieldClause(fieldName, itemName, Occurance.SHOULD_OCCUR);
}
return addClause(inClause.build());
}
/**
* Add a clause which matches a collection containing at least one of several specified
* values (analogous to a SQL "IN" or "NOT IN" statements).
* @param collectionFieldName the collection field name.
* @param itemNames the item names in the collection to match.
* @return a reference to this object.
*/
public Builder addInCollectionItemClause(String collectionFieldName,
Collection itemNames) {
String collectionItemFieldName = QuerySpecification.buildCollectionItemName(
collectionFieldName);
return addInClause(collectionItemFieldName, itemNames);
}
/**
* Add a clause with the given occurance which matches a collection containing at least one of several
* specified values (analogous to a SQL "IN" or "NOT IN" statements).
* @param collectionFieldName the collection field name.
* @param itemNames the item names in the collection to match.
* @param occurance the occurance for this clause.
* @return a reference to this object.
*/
public Builder addInCollectionItemClause(String collectionFieldName,
Collection itemNames, Occurance occurance) {
String collectionItemFieldName = QuerySpecification.buildCollectionItemName(
collectionFieldName);
return addInClause(collectionItemFieldName, itemNames, occurance);
}
/**
* Add a clause which matches a nested field value.
* @param parentFieldName the top level field name.
* @param nestedFieldName the nested field name.
* @param nestedFieldValue the nested field value to match.
* @return a reference to this object.
*/
public Builder addCompositeFieldClause(String parentFieldName, String nestedFieldName,
String nestedFieldValue) {
return addFieldClause(
QuerySpecification.buildCompositeFieldName(parentFieldName, nestedFieldName),
nestedFieldValue);
}
/**
* Add a clause with the given occurance which matches a nested field value.
* @param parentFieldName the top level field name.
* @param nestedFieldName the nested field name.
* @param nestedFieldValue the nested field value to match.
* @param occurance the occurance for this clause.
* @return a reference to this object.
*/
public Builder addCompositeFieldClause(String parentFieldName, String nestedFieldName,
String nestedFieldValue, Occurance occurance) {
return addFieldClause(
QuerySpecification.buildCompositeFieldName(parentFieldName, nestedFieldName),
nestedFieldValue,
occurance);
}
/**
* Add a {@link Occurance#MUST_OCCUR} clause which matches a top level field name using
* {@link MatchType#TERM}.
* @param fieldName the top level field name.
* @param fieldValue the field value to match.
* @return a reference to this object.
*/
public Builder addFieldClause(String fieldName, String fieldValue) {
return addFieldClause(fieldName, fieldValue, MatchType.TERM, Occurance.MUST_OCCUR);
}
/**
* Add a {@link Occurance#MUST_OCCUR} clause which matches a top level field name using
* {@link MatchType#TERM}.
* @param fieldName the top level field name.
* @param fieldValue the field value to match.
* @return a reference to this object.
*/
public Builder addFieldClause(String fieldName, Object fieldValue) {
return addFieldClause(fieldName,
QuerySpecification.toMatchValue(fieldValue),
MatchType.TERM,
Occurance.MUST_OCCUR);
}
/**
* Add a {@link Occurance#MUST_OCCUR} clause which matches a top level field name with the provided
* {@link MatchType}
* @param fieldName the top level field name.
* @param fieldValue the field value to match.
* @param matchType the match type.
* @return a reference to this object.
*/
public Builder addFieldClause(String fieldName, String fieldValue, MatchType matchType) {
return addFieldClause(fieldName, fieldValue, matchType, Occurance.MUST_OCCUR);
}
/**
* Add a clause which matches a top level field name using {@link MatchType#TERM} with the provided
* {@link Occurance}.
* @param fieldName the top level field name.
* @param fieldValue the field value to match.
* @param occurance the {@link Occurance} for this clause.
* @return a reference to this object.
*/
public Builder addFieldClause(String fieldName, String fieldValue, Occurance occurance) {
return addFieldClause(fieldName, fieldValue, MatchType.TERM, occurance);
}
/**
* Add a clause which matches a top level field name with the provided {@link MatchType} and
* {@link Occurance}.
* @param fieldName the top level field name.
* @param fieldValue the field value to match.
* @param matchType the match type.
* @param occurance the {@link Occurance} for this clause.
* @return a reference to this object.
*/
public Builder addFieldClause(String fieldName, String fieldValue, MatchType matchType,
Occurance occurance) {
Query clause = new Query()
.setTermPropertyName(fieldName)
.setTermMatchValue(fieldValue)
.setTermMatchType(matchType);
clause.occurance = occurance;
this.query.addBooleanClause(clause);
return this;
}
/**
* Add a clause which matches a top level field name with the provided {@link MatchType} and
* {@link Occurance}.
* @param fieldName the top level field name.
* @param fieldValue the field value to match, first converted so it can match in a case insensitive way
* @param matchType the match type.
* @param occurance the {@link Occurance} for this clause.
* @return a reference to this object.
*/
public Builder addCaseInsensitiveFieldClause(String fieldName, String fieldValue,
MatchType matchType,
Occurance occurance) {
Query clause = new Query()
.setTermPropertyName(fieldName)
.setCaseInsensitiveTermMatchValue(fieldValue)
.setTermMatchType(matchType);
clause.occurance = occurance;
this.query.addBooleanClause(clause);
return this;
}
/**
* Set the term.
*
* This is only appropriate if you need to query on exactly a single clause and
* it is not compatible with the using multiple boolean clauses, as addFieldClause does.
*
* This assumes you are matching with MatchType.TERM
*
* @param fieldName the top level field name
* @param fieldValue the field value to match
* @return
*/
public Builder setTerm(String fieldName, String fieldValue) {
return setTerm(fieldName, fieldValue, MatchType.TERM);
}
/**
* Set the term.
*
* This is only appropriate if you need to query on exactly a single clause and
* it is not compatible with the using multiple boolean clauses, as addFieldClause does.
*
* This assumes you are matching with MatchType.TERM
*
* @param fieldName the top level field name
* @param fieldValue the field value to match
* @return
*/
public Builder setTerm(String fieldName, String fieldValue, MatchType matchType) {
this.query.term = new QueryTerm();
this.query.term.propertyName = fieldName;
this.query.term.matchValue = fieldValue;
this.query.term.matchType = matchType;
return this;
}
/**
* Add a clause which matches a {@link NumericRange} for a given numeric field.
* @param fieldName the top level numeric field name.
* @param range a numeric range.
* @return a reference to this object.
*/
public Builder addRangeClause(String fieldName, NumericRange> range) {
return addRangeClause(fieldName, range, Occurance.MUST_OCCUR);
}
/**
* Add a clause with the given occurance which matches a {@link NumericRange} for a given numeric field.
* @param fieldName the top level numeric field name.
* @param range a numeric range.
* @param occurance the {@link Occurance} for this clause.
* @return a reference to this object.
*/
public Builder addRangeClause(String fieldName, NumericRange> range,
Occurance occurance) {
Query clause = new Query()
.setTermPropertyName(fieldName)
.setNumericRange(range);
clause.occurance = occurance;
this.query.addBooleanClause(clause);
return this;
}
/**
* Add a clause to this query.
* @param clause a clause.
* @return a reference to this object.
*/
public Builder addClause(Query clause) {
this.query.addBooleanClause(clause);
return this;
}
public Builder addClauses(Query clause1, Query clause2) {
this.query.addBooleanClause(clause1)
.addBooleanClause(clause2);
return this;
}
public Builder addClauses(Query clause1, Query clause2, Query clause3) {
this.query.addBooleanClause(clause1)
.addBooleanClause(clause2)
.addBooleanClause(clause3);
return this;
}
public Builder addClauses(Query firstClause, Query... otherClauses) {
this.query.addBooleanClause(firstClause);
for (Query clause : otherClauses) {
this.query.addBooleanClause(clause);
}
return this;
}
/**
* Return the constructed {@link com.vmware.xenon.services.common.QueryTask.Query} object.
* @return the query object.
*/
public Query build() {
return this.query;
}
}
public Occurance occurance = Occurance.MUST_OCCUR;
/**
* A single term definition.
*
* The {@code booleanClauses} property must be null if this property is specified.
*/
public QueryTerm term;
/**
* A boolean query definition, composed out multiple sub queries.
*
* The {@code term} property must be null if this property is specified.
*/
public List booleanClauses;
public Query setTermPropertyName(String name) {
allocateTerm();
this.term.propertyName = name;
return this;
}
public Query setCaseInsensitiveTermMatchValue(String matchValue) {
return setTermMatchValue(matchValue.toLowerCase());
}
public Query setTermMatchValue(String matchValue) {
allocateTerm();
if (this.term.matchType == null) {
this.term.matchType = MatchType.TERM;
}
this.term.matchValue = matchValue;
return this;
}
public Query setTermMatchType(MatchType matchType) {
allocateTerm();
this.term.matchType = matchType;
return this;
}
public Query setOccurance(Occurance occur) {
this.occurance = occur;
return this;
}
public Query setNumericRange(NumericRange> range) {
allocateTerm();
this.term.range = range;
return this;
}
private void allocateTerm() {
if (this.term != null) {
return;
}
this.term = new QueryTerm();
}
public Query addBooleanClause(Query clause) {
if (this.booleanClauses == null) {
this.booleanClauses = new ArrayList<>();
this.term = null;
}
this.booleanClauses.add(clause);
return this;
}
}
/**
* A list of authorization context links which can access this service.
*/
public List tenantLinks;
/**
* Task state
*/
public TaskState taskInfo = new TaskState();
/**
* Describes the query
*/
public QuerySpecification querySpec;
/**
* Query results
*/
public ServiceDocumentQueryResult results;
/**
* The index service to query documents for. Unless otherwise specified, we default to the
* document index.
*/
public String indexLink = ServiceUriPaths.CORE_DOCUMENT_INDEX;
/**
* The node selector to use when {@link QueryOption#BROADCAST} is set
*/
public String nodeSelectorLink = ServiceUriPaths.DEFAULT_NODE_SELECTOR;
public static QueryTask create(QuerySpecification q) {
QueryTask qt = new QueryTask();
qt.querySpec = q;
return qt;
}
public QueryTask setDirect(boolean enable) {
this.taskInfo.isDirect = enable;
return this;
}
/**
* Builder class for constructing {@linkplain com.vmware.xenon.services.common.QueryTask query tasks}.
*/
public static class Builder {
private final QueryTask queryTask;
private final QuerySpecification querySpec;
private Builder(boolean isDirect) {
this.queryTask = new QueryTask();
this.querySpec = new QuerySpecification();
this.queryTask.querySpec = this.querySpec;
this.queryTask.taskInfo.isDirect = isDirect;
}
/**
* Constructs an asynchronous query task.
* @return a reference to this object.
*/
public static Builder create() {
return new Builder(false);
}
/**
* Constructs a synchronous query task.
* @return a reference to this object.
*/
public static Builder createDirectTask() {
return new Builder(true);
}
/**
* Set the maximum number of results to return.
* @param resultLimit the result limit.
* @return a reference to this object.
*/
public Builder setResultLimit(int resultLimit) {
this.querySpec.resultLimit = resultLimit;
return this;
}
/**
* Set the maximum number of groups to return.
* @param resultLimit the result limit.
* @return a reference to this object.
*/
public Builder setGroupResultLimit(int resultLimit) {
this.querySpec.groupResultLimit = resultLimit;
return this;
}
public Builder setOffset(int offset) {
this.querySpec.offset = offset;
return this;
}
/**
* Set the expected number of results.
* @param expectedResultCount the expected result count.
* @return a reference to this object.
*/
public Builder setExpectedResultCount(long expectedResultCount) {
this.querySpec.expectedResultCount = expectedResultCount;
return this;
}
/**
* Order results in ascending order by the given {@code fieldName}.
* @param fieldName the field name to order results by.
* @param fieldType the field type.
* @return a reference to this object.
*/
public Builder orderAscending(String fieldName, TypeName fieldType) {
return order(fieldName, fieldType, SortOrder.ASC);
}
/**
* Order results in descending order by the given {@code fieldName}.
* @param fieldName the field name to order results by.
* @param fieldType the field type.
* @return a reference to this object.
*/
public Builder orderDescending(String fieldName, TypeName fieldType) {
return order(fieldName, fieldType, SortOrder.DESC);
}
private Builder order(String fieldName, TypeName fieldType, SortOrder sortOrder) {
QueryTerm sortTerm = new QueryTerm();
sortTerm.propertyName = fieldName;
sortTerm.propertyType = fieldType;
if (this.querySpec.sortTerm == null) {
this.querySpec.sortTerm = sortTerm;
this.querySpec.sortOrder = sortOrder;
} else {
sortTerm.sortOrder = sortOrder;
if (this.querySpec.additionalSortTerms == null) {
this.querySpec.additionalSortTerms = new ArrayList<>();
}
this.querySpec.additionalSortTerms.add(sortTerm);
}
addOption(QueryOption.SORT);
return this;
}
/**
* Order group results in specified order by the given {@code fieldName}.
* This method implicitly calls {@link #setGroupByTerm(String, TypeName)}
* @param fieldName the field name to order results by.
* @param fieldType the field type.
* @return a reference to this object.
*/
public Builder groupOrder(String fieldName, TypeName fieldType, SortOrder sortOrder) {
QueryTerm sortTerm = new QueryTerm();
setGroupByTerm(fieldName, fieldType);
sortTerm.propertyName = fieldName;
sortTerm.propertyType = fieldType;
this.querySpec.groupSortTerm = sortTerm;
this.querySpec.groupSortOrder = sortOrder;
return this;
}
/**
* Add the given {@linkplain QueryOption query option}.
* @param queryOption the query option to add.
* @return a reference to this object.
*/
public Builder addOption(QueryOption queryOption) {
this.querySpec.options.add(queryOption);
return this;
}
/**
* Add all of the provided query options to the current set of options.
* @param queryOptions the set of query options to add.
* @return a reference to this object.
*/
public Builder addOptions(EnumSet queryOptions) {
this.querySpec.options.addAll(queryOptions);
return this;
}
/**
* Add the given link field name to the {@code QuerySpecification#linkTerms}
*/
public Builder addLinkTerm(String linkFieldName) {
QueryTerm linkTerm = new QueryTerm();
linkTerm.propertyName = linkFieldName;
linkTerm.propertyType = TypeName.STRING;
if (this.querySpec.linkTerms == null) {
this.querySpec.linkTerms = new ArrayList<>();
}
this.querySpec.linkTerms.add(linkTerm);
return this;
}
/**
* Add the given field name to the {@code QuerySpecification#fieldTerms}
*/
public Builder addSelectTerm(String selectFieldName) {
QueryTerm fieldTerm = new QueryTerm();
fieldTerm.propertyName = selectFieldName;
fieldTerm.propertyType = TypeName.STRING;
if (this.querySpec.selectTerms == null) {
this.querySpec.selectTerms = new ArrayList<>();
}
this.querySpec.selectTerms.add(fieldTerm);
return this;
}
/**
* Sets the {@code QuerySpecification#groupByTerm}
*/
public Builder setGroupByTerm(String fieldName) {
return setGroupByTerm(fieldName, TypeName.STRING);
}
/**
* Sets the {@code QuerySpecification#groupByTerm}
*/
public Builder setGroupByTerm(String fieldName, TypeName fieldType) {
QueryTerm term = new QueryTerm();
term.propertyName = fieldName;
term.propertyType = fieldType;
this.querySpec.groupByTerm = term;
return this;
}
/**
* Set the {@link com.vmware.xenon.services.common.QueryTask.Query} for this task.
* @param query the query to execute.
* @return a reference to this object.
*/
public Builder setQuery(Query query) {
this.querySpec.query = query;
return this;
}
/**
* Set the index service to query for. Defaults to
* {@link ServiceUriPaths#CORE_DOCUMENT_INDEX}
* @param indexLink the index service link.
* @return a reference to this object.
*/
public Builder setIndexLink(String indexLink) {
this.queryTask.indexLink = indexLink;
return this;
}
/**
*
*/
public Builder setQueryTimeStamp(Long documentsUpdatedBeforeInMicros) {
this.querySpec.timeSnapshotBoundaryMicros = documentsUpdatedBeforeInMicros;
return this;
}
/**
* Return the constructed {@link com.vmware.xenon.services.common.QueryTask} object.
* @return the query task object.
*/
public QueryTask build() {
return this.queryTask;
}
}
}