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 2014-2024 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2014-2024 Ping Identity Corporation
*
* 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.
*/
/*
* Copyright (C) 2014-2024 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk.unboundidds.controls;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.unboundid.asn1.ASN1Boolean;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.asn1.ASN1Integer;
import com.unboundid.asn1.ASN1Long;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1Sequence;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPInterface;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.RootDSE;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import com.unboundid.util.json.JSONBoolean;
import com.unboundid.util.json.JSONField;
import com.unboundid.util.json.JSONNumber;
import com.unboundid.util.json.JSONObject;
import com.unboundid.util.json.JSONValue;
import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
/**
* This class provides a request control which may be included in a search
* request to indicate that the server should provide the number of entries that
* match the search criteria. The count will be included in the search result
* done message, and all search result entries will be suppressed.
*
*
* NOTE: This class, and other classes within the
* {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
* supported for use against Ping Identity, UnboundID, and
* Nokia/Alcatel-Lucent 8661 server products. These classes provide support
* for proprietary functionality or for external specifications that are not
* considered stable or mature enough to be guaranteed to work in an
* interoperable way with other types of LDAP servers.
*
*
* Whenever possible, the server will use index information to quickly identify
* entries matching the criteria of the associated search request. However, if
* the count is only determined using index information, then that count may
* include entries that would not actually be returned to the client in the
* course of processing that search (e.g., because the client doesn't have
* permission to access the entry, or because it is a special "operational"
* entry like an LDAP subentry, replication conflict entry, or soft-deleted
* entry). Indicating that the server should always examine candidate entries
* will increase the length of time to obtain the matching entry count, but will
* ensure that the count will not include entries that would not otherwise be
* returned by that search.
*
* Also note that this control is not compatible for use with other controls
* that may cause only a subset of entries to be returned, including the simple
* paged results control and the virtual list view control. It is also not
* compatible for use with other controls that may cause the server to return
* more entries than those that match the search criteria, like the LDAP join
* control.
*
* The OID for a matching entry count request control is
* "1.3.6.1.4.1.30221.2.5.36", and it may have a criticality of either
* {@code true} or {@code false}. It must include a value with the following
* encoding:
*
*
* @see MatchingEntryCountResponseControl
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class MatchingEntryCountRequestControl
extends Control
{
/**
* The OID (1.3.6.1.4.1.30221.2.5.36) for the matching entry count request
* control.
*/
@NotNull public static final String MATCHING_ENTRY_COUNT_REQUEST_OID =
"1.3.6.1.4.1.30221.2.5.36";
/**
* The OID (1.3.6.1.4.1.30221.2.12.7) for the supportedFeature value that a
* server should advertise in its root DSE if it supports returning extended
* information in the response control that older clients may not be able to
* handle. Clients that wish to use the {@code includeExtendedResponseData}
* element of the request control should check the target server's root DSE
* to determine whether it supports this feature before requesting it because
* older versions of the server that do not support it may not accept a
* control that requests it.
*/
@NotNull public static final String EXTENDED_RESPONSE_DATA_FEATURE_OID =
"1.3.6.1.4.1.30221.2.12.7";
/**
* The BER type for the element that specifies the maximum number of candidate
* entries to examine.
*/
private static final byte TYPE_MAX_CANDIDATES_TO_EXAMINE = (byte) 0x80;
/**
* The BER type for the element that indicates whether always examine
* candidate entries to determine whether they would actually be returned to
* the client.
*/
private static final byte TYPE_ALWAYS_EXAMINE_CANDIDATES = (byte) 0x81;
/**
* The BER type for the element that indicates whether to process an unindexed
* search to determine the number of matching entries.
*/
private static final byte TYPE_PROCESS_SEARCH_IF_UNINDEXED = (byte) 0x82;
/**
* The BER type for the element that indicates whether to include debug
* information in the response.
*/
private static final byte TYPE_INCLUDE_DEBUG_INFO = (byte) 0x83;
/**
* The BER type for the element that indicates whether to skip resolving
* exploded indexes if the number of matching entries is known.
*/
private static final byte TYPE_SKIP_RESOLVING_EXPLODED_INDEXES = (byte) 0x84;
/**
* The BER type for the element that specifies the short-circuit threshold to
* use when performing index processing that is expected to be very fast
* (e.g., filter components that can be evaluated with a single index lookup,
* like presence, equality, and approximate match components).
*/
private static final byte TYPE_FAST_SHORT_CIRCUIT_THRESHOLD = (byte) 0x85;
/**
* The BER type for the element that specifies the short-circuit threshold to
* use when evaluating filter components that are not covered by the fast
* short-circuit threshold.
*/
private static final byte TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD = (byte) 0x86;
/**
* The BER type for the element that indicates whether the client wants the
* server to return extended information in the response, including elements
* that may indicate whether all of the identified candidate entries are
* within the scope of the search and any portion of the filter that is
* unindexed or unevaluated.
*/
private static final byte TYPE_INCLUDE_EXTENDED_RESPONSE_DATA = (byte) 0x87;
/**
* The name of the field used to hold the always examine candidates flag in
* the JSON representation of this control.
*/
@NotNull private static final String JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES =
"always-examine-candidates";
/**
* The name of the field used to hold the fast short-circuit threshold in the
* JSON representation of this control.
*/
@NotNull private static final String JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD =
"fast-short-circuit-threshold";
/**
* The name of the field used to hold the include debug info flag in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_INCLUDE_DEBUG_INFO =
"include-debug-info";
/**
* The name of the field used to hold the include extended response data flag
* in the JSON representation of this control.
*/
@NotNull private static final String
JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA =
"include-extended-response-data";
/**
* The name of the field used to hold the maximum candidates to examine in the
* JSON representation of this control.
*/
@NotNull private static final String
JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE =
"maximum-candidates-to-examine";
/**
* The name of the field used to hold the process search if unindexed flag in
* the JSON representation of this control.
*/
@NotNull private static final String JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED =
"process-search-if-unindexed";
/**
* The name of the field used to hold the skip resolving exploded indexes flag
* in the JSON representation of this control.
*/
@NotNull private static final String
JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES =
"skip-resolving-exploded-indexes";
/**
* The name of the field used to hold the slow short-circuit threshold in the
* JSON representation of this control.
*/
@NotNull private static final String JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD =
"slow-short-circuit-threshold";
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 8670611963939571953L;
// Indicates whether the server should internally retrieve and examine
// candidate entries to determine whether they would actually be returned to
// the client.
private final boolean alwaysExamineCandidates;
// Indicates whether to include debug information in the response control.
private final boolean includeDebugInfo;
// Indicates whether to include extended information in the response.
private final boolean includeExtendedResponseData;
// Indicates whether the server should attempt to actually iterate through the
// entries in the backend in order to obtain the count if the search criteria
// is not indexed.
private final boolean processSearchIfUnindexed;
// Indicates whether the server should skip retrieving the entry ID set for
// an exploded index key if the number of matching entries is known.
private final boolean skipResolvingExplodedIndexes;
// The maximum number of candidate entries that should be examined if it is
// not possible to obtain an exact count using only information contained in
// the server indexes.
private final int maxCandidatesToExamine;
// The short-circuit threshold that the server will use when evaluating filter
// components that are not categorized as fast.
@Nullable private final Long slowShortCircuitThreshold;
// The short-circuit threshold that the server will for index processing that
// should be very fast.
@Nullable private final Long fastShortCircuitThreshold;
/**
* Creates a new matching entry count request control with the default
* settings. The control will be critical, no candidate entries will be
* examined, and the search will not be processed if it is unindexed.
*/
public MatchingEntryCountRequestControl()
{
this(true, 0, false, false, false);
}
/**
* Creates a new matching entry count request control with the provided
* information.
*
* @param isCritical Indicates whether this control should be
* critical.
* @param maxCandidatesToExamine The maximum number of candidate entries
* that the server should retrieve and
* examine to determine whether they
* actually match the search criteria. If
* the search is partially indexed and the
* total number of candidate entries is less
* than or equal to this value, then these
* candidate entries will be examined to
* determine which of them match the search
* criteria so that an accurate count can
* be determined. If the search is fully
* indexed such that the all candidate
* entries are known to match the search
* criteria, then the server may still
* examine each of these entries if the
* number of candidates is less than
* {@code maxCandidatesToExamine} and
* {@code alwaysExamineCandidates} is true
* in order to allow the entry count that
* is returned to be restricted to only
* those entries that would actually be
* returned to the client. This will be
* ignored for searches that are completely
* unindexed.
*
* The value for this argument must be
* greater than or equal to zero. If it
* is zero, then the server will not
* examine any entries, so a
* partially-indexed search will only be
* able to return a count that is an upper
* bound, and a fully-indexed search will
* only be able to return an unexamined
* exact count. If there should be no bound
* on the number of entries to retrieve,
* then a value of {@code Integer.MAX_VALUE}
* may be specified.
* @param alwaysExamineCandidates Indicates whether the server should
* always examine candidate entries to
* determine whether they would actually
* be returned to the client in a normal
* search. This will only be used for
* fully-indexed searches in which the
* set of matching entries is known. If the
* value is {@code true} and the number of
* candidates is smaller than
* {@code maxCandidatesToExamine}, then each
* matching entry will be internally
* retrieved and examined to determine
* whether it would be returned to the
* client based on the details of the search
* request (e.g., whether the requester has
* permission to access the entry, whether
* it's an LDAP subentry, replication
* conflict entry, soft-deleted entry, or
* other type of entry that is normally
* hidden) so that an exact count can be
* returned. If this is {@code false} or
* the number of candidates exceeds
* {@code maxCandidatesToExamine}, then the
* server will only be able to return an
* unexamined count which may include
* entries that match the search criteria
* but that would not normally be returned
* to the requester.
* @param processSearchIfUnindexed Indicates whether the server should
* attempt to determine the number of
* matching entries if the search criteria
* is completely unindexed. If this is
* {@code true} and the requester has the
* unindexed-search privilege, then the
* server will iterate through all entries
* in the scope (which may take a very long
* time to complete) in order to to
* determine which of them match the search
* criteria so that it can return an
* accurate count. If this is
* {@code false} or the requester does not
* have the unindexed-search privilege, then
* the server will not spend any time
* attempting to determine the number of
* matching entries and will instead return
* a matching entry count response control
* indicating that the entry count is
* unknown.
* @param includeDebugInfo Indicates whether the server should
* include debug information in the response
* that may help better understand how it
* arrived at the result. If any debug
* information is returned, it will be in
* the form of human-readable text that is
* not intended to be machine-parsable.
*/
public MatchingEntryCountRequestControl(final boolean isCritical,
final int maxCandidatesToExamine,
final boolean alwaysExamineCandidates,
final boolean processSearchIfUnindexed,
final boolean includeDebugInfo)
{
this(isCritical, maxCandidatesToExamine, alwaysExamineCandidates,
processSearchIfUnindexed, false, null, null, includeDebugInfo);
}
/**
* Creates a new matching entry count request control with the provided
* information.
*
* @param isCritical Indicates whether this control should
* be critical.
* @param maxCandidatesToExamine The maximum number of candidate
* entries that the server should
* retrieve and examine to determine
* whether they actually match the
* search criteria. If the search is
* partially indexed and the total
* number of candidate entries is less
* than or equal to this value, then
* these candidate entries will be
* examined to determine which of them
* match the search criteria so that an
* accurate count can be determined. If
* the search is fully indexed such that
* the all candidate entries are known
* to match the search criteria, then
* the server may still examine each of
* these entries if the number of
* candidates is less than
* {@code maxCandidatesToExamine} and
* {@code alwaysExamineCandidates} is
* {@code true} in order to allow the
* entry count that is returned to be
* restricted to only those entries that
* would actually be returned to the
* client. This will be ignored for
* searches that are completely
* unindexed.
*
* The value for this argument must be
* greater than or equal to zero. If it
* is zero, then the server will not
* examine any entries, so a
* partially-indexed search will only be
* able to return a count that is an
* upper bound, and a fully-indexed
* search will only be able to return an
* unexamined exact count. If there
* should be no bound on the number of
* entries to retrieve, then a value of
* {@code Integer.MAX_VALUE} may be
* specified.
* @param alwaysExamineCandidates Indicates whether the server should
* always examine candidate entries to
* determine whether they would actually
* be returned to the client in a normal
* search. This will only be used for
* fully-indexed searches in which the
* set of matching entries is known. If
* the value is {@code true} and the
* number of candidates is smaller than
* {@code maxCandidatesToExamine}, then
* each matching entry will be
* internally retrieved and examined to
* determine whether it would be
* returned to the client based on the
* details of the search request (e.g.,
* whether the requester has permission
* to access the entry, whether it's an
* LDAP subentry, replication conflict
* entry, soft-deleted entry, or other
* type of entry that is normally
* hidden, etc.) so that an exact count
* can be returned. If this is
* {@code false} or the number of
* candidates exceeds
* {@code maxCandidatesToExamine}, then
* the server will only be able to
* return an unexamined count which may
* include entries that match the search
* criteria but that would not normally
* be returned to the requester.
* @param processSearchIfUnindexed Indicates whether the server should
* attempt to determine the number of
* matching entries if the search
* criteria is completely unindexed. If
* this is {@code true} and the
* requester has the unindexed-search
* privilege, then the server will
* iterate through all entries in the
* scope (which may take a very long
* time to complete) in order to to
* determine which of them match the
* search criteria so that it can return
* an accurate count. If this is
* {@code false} or the requester does
* not have the unindexed-search
* privilege, then the server will not
* spend any time attempting to
* determine the number of matching
* entries and will instead return a
* matching entry count response control
* indicating that the entry count is
* unknown.
* @param skipResolvingExplodedIndexes Indicates whether the server should
* skip the effort of actually
* retrieving the candidate entry IDs
* for exploded index keys in which the
* number of matching entries is known.
* Skipping the process of retrieving
* the candidate entry IDs can allow the
* server to more quickly estimate the
* matching entry count, but the
* resulting estimate may be less
* accurate.
* @param fastShortCircuitThreshold Specifies the short-circuit threshold
* that the server should use when
* determining whether to continue with
* index processing in an attempt to
* further pare down a candidate set
* that already has a defined superset
* of the entries that actually match
* the filter. Short-circuiting may
* allow the server to skip
* potentially-costly index processing
* and allow it to obtain the matching
* entry count estimate faster, but the
* resulting estimate may be less
* accurate. The fast short-circuit
* threshold will be used for index
* processing that is expected to be
* very fast (e.g., when performing
* index lookups for presence, equality,
* and approximate-match components,
* which should only require accessing a
* single index key). A value that is
* less than or equal to zero indicates
* that the server should never short
* circuit when performing fast index
* processing. A value of {@code null}
* indicates that the server should
* determine the appropriate fast
* short-circuit threshold to use.
* @param slowShortCircuitThreshold Specifies the short-circuit threshold
* that the server should use when
* determining whether to continue with
* index processing for evaluation that
* may be more expensive than what falls
* into the "fast" category (e.g.,
* substring and range filter
* components). A value that is less
* than or equal to zero indicates that
* the server should never short circuit
* when performing slow index
* processing. A value of {@code null}
* indicates that the server should
* determine the appropriate slow
* short-circuit threshold to use.
* @param includeDebugInfo Indicates whether the server should
* include debug information in the
* response that may help better
* understand how it arrived at the
* result. If any debug information is
* returned, it will be in the form of
* human-readable text that is not
* intended to be machine-parsable.
*/
public MatchingEntryCountRequestControl(final boolean isCritical,
final int maxCandidatesToExamine,
final boolean alwaysExamineCandidates,
final boolean processSearchIfUnindexed,
final boolean skipResolvingExplodedIndexes,
@Nullable final Long fastShortCircuitThreshold,
@Nullable final Long slowShortCircuitThreshold,
final boolean includeDebugInfo)
{
super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical,
encodeValue(maxCandidatesToExamine, alwaysExamineCandidates,
processSearchIfUnindexed, skipResolvingExplodedIndexes,
fastShortCircuitThreshold, slowShortCircuitThreshold, false,
includeDebugInfo));
Validator.ensureTrue(maxCandidatesToExamine >= 0);
this.maxCandidatesToExamine = maxCandidatesToExamine;
this.alwaysExamineCandidates = alwaysExamineCandidates;
this.processSearchIfUnindexed = processSearchIfUnindexed;
this.skipResolvingExplodedIndexes = skipResolvingExplodedIndexes;
this.includeDebugInfo = includeDebugInfo;
if (fastShortCircuitThreshold == null)
{
this.fastShortCircuitThreshold = null;
}
else
{
this.fastShortCircuitThreshold = Math.max(0L, fastShortCircuitThreshold);
}
if (slowShortCircuitThreshold == null)
{
this.slowShortCircuitThreshold = null;
}
else
{
this.slowShortCircuitThreshold = Math.max(0L, slowShortCircuitThreshold);
}
includeExtendedResponseData = false;
}
/**
* Creates a new matching entry count request control with the provided
* properties.
*
* @param isCritical Indicates whether the control should be critical.
* @param properties The properties that should be used to create this
* matching entry count request control. It must not be
* {@code null}.
*/
public MatchingEntryCountRequestControl(final boolean isCritical,
@NotNull final MatchingEntryCountRequestControlProperties properties)
{
super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical,
encodeValue(properties.getMaxCandidatesToExamine(),
properties.alwaysExamineCandidates(),
properties.processSearchIfUnindexed(),
properties.skipResolvingExplodedIndexes(),
properties.getFastShortCircuitThreshold(),
properties.getSlowShortCircuitThreshold(),
properties.includeExtendedResponseData(),
properties.includeDebugInfo()));
maxCandidatesToExamine = properties.getMaxCandidatesToExamine();
alwaysExamineCandidates = properties.alwaysExamineCandidates();
processSearchIfUnindexed = properties.processSearchIfUnindexed();
skipResolvingExplodedIndexes = properties.skipResolvingExplodedIndexes();
fastShortCircuitThreshold = properties.getFastShortCircuitThreshold();
slowShortCircuitThreshold = properties.getSlowShortCircuitThreshold();
includeExtendedResponseData = properties.includeExtendedResponseData();
includeDebugInfo = properties.includeDebugInfo();
}
/**
* Creates a new matching entry count request control that is decoded from the
* provided generic control.
*
* @param control The control to decode as a matching entry count request
* control.
*
* @throws LDAPException If the provided control cannot be decoded as a
* matching entry count request control.
*/
public MatchingEntryCountRequestControl(@NotNull final Control control)
throws LDAPException
{
super(control);
final ASN1OctetString value = control.getValue();
if (value == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_MATCHING_ENTRY_COUNT_REQUEST_MISSING_VALUE.get());
}
try
{
boolean alwaysExamine = false;
boolean debug = false;
boolean includeExtended = false;
boolean processUnindexed = false;
boolean skipExploded = false;
int maxCandidates = 0;
Long fastSCThreshold = null;
Long slowSCThreshold = null;
final ASN1Element[] elements =
ASN1Sequence.decodeAsSequence(value.getValue()).elements();
for (final ASN1Element e : elements)
{
switch (e.getType())
{
case TYPE_MAX_CANDIDATES_TO_EXAMINE:
maxCandidates = ASN1Integer.decodeAsInteger(e).intValue();
if (maxCandidates < 0)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_MATCHING_ENTRY_COUNT_REQUEST_INVALID_MAX.get());
}
break;
case TYPE_ALWAYS_EXAMINE_CANDIDATES:
alwaysExamine = ASN1Boolean.decodeAsBoolean(e).booleanValue();
break;
case TYPE_PROCESS_SEARCH_IF_UNINDEXED:
processUnindexed = ASN1Boolean.decodeAsBoolean(e).booleanValue();
break;
case TYPE_INCLUDE_DEBUG_INFO:
debug = ASN1Boolean.decodeAsBoolean(e).booleanValue();
break;
case TYPE_SKIP_RESOLVING_EXPLODED_INDEXES:
skipExploded = ASN1Boolean.decodeAsBoolean(e).booleanValue();
break;
case TYPE_FAST_SHORT_CIRCUIT_THRESHOLD:
fastSCThreshold =
Math.max(0L, ASN1Long.decodeAsLong(e).longValue());
break;
case TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD:
slowSCThreshold =
Math.max(0L, ASN1Long.decodeAsLong(e).longValue());
break;
case TYPE_INCLUDE_EXTENDED_RESPONSE_DATA:
includeExtended = ASN1Boolean.decodeAsBoolean(e).booleanValue();
break;
}
}
maxCandidatesToExamine = maxCandidates;
alwaysExamineCandidates = alwaysExamine;
processSearchIfUnindexed = processUnindexed;
includeDebugInfo = debug;
includeExtendedResponseData = includeExtended;
skipResolvingExplodedIndexes = skipExploded;
fastShortCircuitThreshold = fastSCThreshold;
slowShortCircuitThreshold = slowSCThreshold;
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_MATCHING_ENTRY_COUNT_REQUEST_CANNOT_DECODE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Encodes the provided information into an ASN.1 octet string suitable for
* use as the control value.
*
* @param maxCandidatesToExamine The maximum number of candidate
* entries that the server should
* retrieve and examine to determine
* whether they actually match the
* search criteria.
* @param alwaysExamineCandidates Indicates whether the server should
* always examine candidate entries to
* determine whether they would actually
* be returned to the client in a normal
* search with the same criteria.
* @param processSearchIfUnindexed Indicates whether the server should
* attempt to determine the number of
* matching entries if the search
* criteria is completely unindexed.
* @param skipResolvingExplodedIndexes Indicates whether the server should
* skip the effort of actually
* retrieving the candidate entry IDs
* for exploded index keys in which the
* number of matching entries is known.
* @param fastShortCircuitThreshold Specifies the short-circuit threshold
* that the server should use when
* determining whether to continue with
* index processing for fast index
* processing.
* @param slowShortCircuitThreshold Specifies the short-circuit threshold
* that the server should use when
* determining whether to continue with
* index processing for slow index
* processing.
* @param includeExtendedResponseData Indicates whether the server may
* include extended response data in the
* corresponding response control.
* @param includeDebugInfo Indicates whether the server should
* include debug information in the
* response that may help better
* understand how it arrived at the
* result.
*
* @return The ASN.1 octet string containing the encoded control value.
*/
@NotNull()
private static ASN1OctetString encodeValue(
final int maxCandidatesToExamine,
final boolean alwaysExamineCandidates,
final boolean processSearchIfUnindexed,
final boolean skipResolvingExplodedIndexes,
@Nullable final Long fastShortCircuitThreshold,
@Nullable final Long slowShortCircuitThreshold,
final boolean includeExtendedResponseData,
final boolean includeDebugInfo)
{
final ArrayList elements = new ArrayList<>(4);
if (maxCandidatesToExamine > 0)
{
elements.add(new ASN1Integer(TYPE_MAX_CANDIDATES_TO_EXAMINE,
maxCandidatesToExamine));
}
if (alwaysExamineCandidates)
{
elements.add(new ASN1Boolean(TYPE_ALWAYS_EXAMINE_CANDIDATES, true));
}
if (processSearchIfUnindexed)
{
elements.add(new ASN1Boolean(TYPE_PROCESS_SEARCH_IF_UNINDEXED, true));
}
if (includeDebugInfo)
{
elements.add(new ASN1Boolean(TYPE_INCLUDE_DEBUG_INFO, true));
}
if (skipResolvingExplodedIndexes)
{
elements.add(new ASN1Boolean(TYPE_SKIP_RESOLVING_EXPLODED_INDEXES, true));
}
if (fastShortCircuitThreshold != null)
{
elements.add(new ASN1Long(TYPE_FAST_SHORT_CIRCUIT_THRESHOLD,
Math.max(0L, fastShortCircuitThreshold)));
}
if (slowShortCircuitThreshold != null)
{
elements.add(new ASN1Long(TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD,
Math.max(0L, slowShortCircuitThreshold)));
}
if (includeExtendedResponseData)
{
elements.add(new ASN1Boolean(TYPE_INCLUDE_EXTENDED_RESPONSE_DATA, true));
}
return new ASN1OctetString(new ASN1Sequence(elements).encode());
}
/**
* Retrieves the maximum number of candidate entries that should be examined
* in order to determine accurate count of the number of matching entries.
*
* For a fully-indexed search, this property will only be used if
* {@link #alwaysExamineCandidates} is true. If the number of candidate
* entries identified is less than the maximum number of candidates to
* examine, then the server will return an {@code EXAMINED_COUNT} result that
* indicates the number of entries matching the criteria that would actually
* be returned in a normal search with the same criteria. If the number of
* candidate entries exceeds the maximum number of candidates to examine, then
* the server will return an {@code UNEXAMINED_COUNT} result that indicates
* the number of entries matching the search criteria but that may include
* entries that would not actually be returned to the client.
*
* For a partially-indexed search, if the upper bound on the number of
* candidates is less than or equal to the maximum number of candidates to
* examine, then the server will internally retrieve and examine each of those
* candidates to determine which of them match the search criteria and would
* actually be returned to the client, and will then return an
* {@code EXAMINED_COUNT} result with that count. If the upper bound on the
* number of candidates is greater than the maximum number of candidates to
* examine, then the server will return an {@code UPPER_BOUND} result to
* indicate that the exact count is not known but an upper bound is available.
*
* @return The maximum number of candidate entries to examine in order to
* determine an accurate count of the number of matching entries.
*/
public int getMaxCandidatesToExamine()
{
return maxCandidatesToExamine;
}
/**
* Indicates whether the server should always examine candidate entries in
* fully-indexed searches to determine whether they would actually be returned
* to the client in a normal search with the same criteria.
*
* @return {@code true} if the server should attempt to internally retrieve
* and examine matching entries to determine whether they would
* normally be returned to the client (e.g., that the client has
* permission to access the entry and that it is not a
* normally-hidden entry like an LDAP subentry, a replication
* conflict entry, or a soft-deleted entry), or {@code false} if the
* server should return an unverified count.
*/
public boolean alwaysExamineCandidates()
{
return alwaysExamineCandidates;
}
/**
* Indicates whether the server should internally retrieve and examine all
* entries within the search scope in order to obtain an exact matching entry
* count for an unindexed search. Note that this value will not be considered
* for completely-indexed or partially-indexed searches, nor for searches in
* which matching entries should be returned.
*
* @return {@code true} if the server should internally retrieve and examine
* all entries within the search scope in order to obtain an exact
* matching entry count for an unindexed search, or {@code false} if
* not.
*/
public boolean processSearchIfUnindexed()
{
return processSearchIfUnindexed;
}
/**
* Indicates whether the server should skip the effort of actually retrieving
* the candidate entry IDs for exploded index keys in which the number of
* matching entries is known. Skipping the process of accessing an exploded
* index can allow the server to more quickly arrive at the matching entry
* count estimate, but that estimate may be less accurate than if it had
* actually retrieved those candidates.
*
* @return {@code true} if the server should skip the effort of actually
* retrieving the candidate entry IDs for exploded index keys in
* which the number of matching entries is known, or {@code false} if
* it may retrieve candidates from an exploded index in the course of
* determining the matching entry count.
*/
public boolean skipResolvingExplodedIndexes()
{
return skipResolvingExplodedIndexes;
}
/**
* Retrieves the short-circuit threshold that the server should use when
* determining whether to continue with index processing in an attempt to
* further pare down a candidate set that already has a defined superset of
* the entries that actually match the filter. If the number of entries in
* that candidate set is less than or equal to the short-circuit threshold,
* then the server may simply use that candidate set in the course of
* determining the matching entry count, even if there may be additional
* processing that can be performed (e.g., further filter components to
* evaluate) that may allow the server to pare down the results even further.
* Short-circuiting may allow the server to obtain the matching entry count
* estimate faster, but may also cause the resulting estimate to be less
* accurate.
*
* The value returned by this method will be used for cases in which the
* server is performing the fastest types of index processing. For example,
* this may include evaluating presence, equality, or approximate match
* components, which should only require retrieving a single index key to
* obtain the candidate set.
*
* @return The short-circuit threshold that should be used for fast index
* processing, zero if the server should not short-circuit at all
* during fast index processing, or {@code null} if the server should
* determine the appropriate fast short-circuit threshold to use.
*/
@Nullable()
public Long getFastShortCircuitThreshold()
{
return fastShortCircuitThreshold;
}
/**
* Retrieves the short-circuit threshold that the server should use when
* determining whether to continue with index processing in an attempt to
* further pare down a candidate set that already has a defined superset of
* the entries that actually match the filter. If the number of entries in
* that candidate set is less than or equal to the short-circuit threshold,
* then the server may simply use that candidate set in the course of
* determining the matching entry count, even if there may be additional
* processing that can be performed (e.g., further filter components to
* evaluate) that may allow the server to pare down the results even further.
* Short-circuiting may allow the server to obtain the matching entry count
* estimate faster, but may also cause the resulting estimate to be less
* accurate.
*
* The value returned by this method will be used for cases in which the
* server is performing index processing that is not considered to be among
* the fastest types of processing. For example, this may include evaluating
* substring and range components, as they may require retrieving many index
* keys to obtain the full candidate set.
*
* @return The short-circuit threshold that should be used for slow index
* processing, or zero if the server should not short-circuit at all
* during slow index processing, or {@code null} if the server should
* determine the appropriate slow short-circuit threshold to use.
*/
@Nullable()
public Long getSlowShortCircuitThreshold()
{
return slowShortCircuitThreshold;
}
/**
* Indicates whether the server may include extended response data in the
* corresponding response control, which may provide information like whether
* all of the identified candidate entries are within the scope of the search
* and any unindexed or unevaluated portion of the search filter.
*
* @return {@code true} if the server may include extended response data
* in the corresponding response control, or {@code false} if not.
*/
public boolean includeExtendedResponseData()
{
return includeExtendedResponseData;
}
/**
* Attempts to determine whether the server to which the provided connection
* is established supports including extended response data in the matching
* entry count response control.
*
* @param connection The connection (or connection pool or other interface)
* to use to communicate with the server. It must not be
* {@code null} and must be established.
*
* @return {@code true} if the server reports that supports including
* extended response data in the matching entry count response
* control, or {@code false} if it does not indicate that it is
* supported.
*
* @throws LDAPException If a problem occurs while attempting to communicate
* with the server.
*/
public static boolean serverSupportsExtendedResponseData(
@NotNull final LDAPInterface connection)
throws LDAPException
{
final RootDSE rootDSE = connection.getRootDSE();
return ((rootDSE != null) && serverSupportsExtendedResponseData(rootDSE));
}
/**
* Determines whether the provided root DSE indicates that the associated
* server supports including extended response data in the matching entry
* count response control.
*
* @param rootDSE The root DSE retrieved from the server for which to make
* the determination. It must not be {@code null}.
*
* @return {@code true} if the root DSE indicates that supports including
* extended response data in the matching entry count response
* control, or {@code false} if not.
*/
public static boolean serverSupportsExtendedResponseData(
@NotNull final RootDSE rootDSE)
{
return rootDSE.supportsFeature(EXTENDED_RESPONSE_DATA_FEATURE_OID);
}
/**
* Indicates whether the server should include debug information in the
* response control that provides additional information about how the server
* arrived at the result. If debug information is to be provided, it will be
* in a human-readable rather than machine-parsable form.
*
* @return {@code true} if the server should include debug information in
* the response control, or {@code false} if not.
*/
public boolean includeDebugInfo()
{
return includeDebugInfo;
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getControlName()
{
return INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get();
}
/**
* Retrieves a representation of this matching entry count request control as
* a JSON object. The JSON object uses the following fields:
*
*
* {@code oid} -- A mandatory string field whose value is the object
* identifier for this control. For the matching entry count request
* control, the OID is "1.3.6.1.4.1.30221.2.5.36".
*
*
* {@code control-name} -- An optional string field whose value is a
* human-readable name for this control. This field is only intended for
* descriptive purposes, and when decoding a control, the {@code oid}
* field should be used to identify the type of control.
*
*
* {@code criticality} -- A mandatory Boolean field used to indicate
* whether this control is considered critical.
*
*
* {@code value-base64} -- An optional string field whose value is a
* base64-encoded representation of the raw value for this matching entry
* count request control. Exactly one of the {@code value-base64} and
* {@code value-json} fields must be present.
*
*
* {@code value-json} -- An optional JSON object field whose value is a
* user-friendly representation of the value for this matching entry count
* request control. Exactly one of the {@code value-base64} and
* {@code value-json} fields must be present, and if the
* {@code value-json} field is used, then it will use the following
* fields:
*
*
* {@code maximum-candidates-to-examine} -- An optional integer field
* whose value indicates the maximum number of entries that the server
* should retrieve and examine to determine whether they actually
* match the search criteria and would be returned to the client.
*
*
* {@code always-examine-candidates} -- An optional Boolean field that
* indicates whether the server should always examine candidates to
* determine whether they would actually be returned to the client,
* even if the search is fully indexed and the server knows that all
* candidates match the search criteria.
*
*
* {@code process-search-if-unindexed} -- An optional Boolean field
* that indicates whether the server should attempt to process the
* search even if the search criteria is completely unindexed.
*
*
* {@code include-debug-info} -- An optional Boolean field
* that indicates whether the server should return debug information
* in the response control about the processing it performed in the
* course of determining the matching entry count estimate.
*
*
* {@code skip-resolving-exploded-indexes} -- An optional Boolean
* field that indicates whether the server should skip the step of
* resolving exploded indexes in cases where the size of the ID set is
* known.
*
*
* {@code fast-short-circuit-threshold} -- An optional integer field
* whose value is the short-circuit threshold that the server should
* use for "fast" filter components.
*
*
* {@code slow-short-circuit-threshold} -- An optional integer field
* whose value is the short-circuit threshold that the server should
* use for "slow" filter components.
*
*
* {@code include-extended-response-data} -- An optional Boolean field
* that indicates whether the server should include extended
* information in the response control.
*
*
*
*
*
* @return A JSON object that contains a representation of this control.
*/
@Override()
@NotNull()
public JSONObject toJSONControl()
{
final Map valueFields = new LinkedHashMap<>();
if (maxCandidatesToExamine > 0)
{
valueFields.put(JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE,
new JSONNumber(maxCandidatesToExamine));
}
else
{
valueFields.put(JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE,
new JSONNumber(0));
}
valueFields.put(JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES,
new JSONBoolean(alwaysExamineCandidates));
valueFields.put(JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED,
new JSONBoolean(processSearchIfUnindexed));
valueFields.put(JSON_FIELD_INCLUDE_DEBUG_INFO,
new JSONBoolean(includeDebugInfo));
valueFields.put(JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES,
new JSONBoolean(skipResolvingExplodedIndexes));
if (fastShortCircuitThreshold != null)
{
valueFields.put(JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD,
new JSONNumber(fastShortCircuitThreshold));
}
if (slowShortCircuitThreshold != null)
{
valueFields.put(JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD,
new JSONNumber(slowShortCircuitThreshold));
}
valueFields.put(JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA,
new JSONBoolean(includeExtendedResponseData));
return new JSONObject(
new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
MATCHING_ENTRY_COUNT_REQUEST_OID),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get()),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
isCritical()),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
new JSONObject(valueFields)));
}
/**
* Attempts to decode the provided object as a JSON representation of a
* matching entry count request control.
*
* @param controlObject The JSON object to be decoded. It must not be
* {@code null}.
* @param strict Indicates whether to use strict mode when decoding
* the provided JSON object. If this is {@code true},
* then this method will throw an exception if the
* provided JSON object contains any unrecognized
* fields. If this is {@code false}, then unrecognized
* fields will be ignored.
*
* @return The matching entry count request control that was decoded from the
* provided JSON object.
*
* @throws LDAPException If the provided JSON object cannot be parsed as a
* valid matching entry count request control.
*/
@NotNull()
public static MatchingEntryCountRequestControl decodeJSONControl(
@NotNull final JSONObject controlObject,
final boolean strict)
throws LDAPException
{
final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
controlObject, strict, true, true);
final ASN1OctetString rawValue = jsonControl.getRawValue();
if (rawValue != null)
{
return new MatchingEntryCountRequestControl(new Control(
jsonControl.getOID(), jsonControl.getCriticality(), rawValue));
}
final JSONObject valueObject = jsonControl.getValueObject();
final MatchingEntryCountRequestControlProperties properties =
new MatchingEntryCountRequestControlProperties();
final Integer maximumCandidatesToExamine = valueObject.getFieldAsInteger(
JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE);
if (maximumCandidatesToExamine == null)
{
properties.setMaxCandidatesToExamine(0);
}
else
{
properties.setMaxCandidatesToExamine(maximumCandidatesToExamine);
}
final Boolean alwaysExamineCandidates =
valueObject.getFieldAsBoolean(JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES);
if (alwaysExamineCandidates == null)
{
properties.setAlwaysExamineCandidates(false);
}
else
{
properties.setAlwaysExamineCandidates(alwaysExamineCandidates);
}
final Boolean processSearchIfUnindexed =
valueObject.getFieldAsBoolean(JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED);
if (processSearchIfUnindexed == null)
{
properties.setProcessSearchIfUnindexed(false);
}
else
{
properties.setProcessSearchIfUnindexed(processSearchIfUnindexed);
}
final Boolean includeDebugInfo =
valueObject.getFieldAsBoolean(JSON_FIELD_INCLUDE_DEBUG_INFO);
if (includeDebugInfo == null)
{
properties.setIncludeDebugInfo(false);
}
else
{
properties.setIncludeDebugInfo(includeDebugInfo);
}
final Boolean skipResolvingExplodedIndexes =
valueObject.getFieldAsBoolean(
JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES);
if (skipResolvingExplodedIndexes == null)
{
properties.setSkipResolvingExplodedIndexes(false);
}
else
{
properties.setSkipResolvingExplodedIndexes(skipResolvingExplodedIndexes);
}
final Long fastShortCircuitThreshold =
valueObject.getFieldAsLong(JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD);
if (fastShortCircuitThreshold != null)
{
properties.setFastShortCircuitThreshold(fastShortCircuitThreshold);
}
final Long slowShortCircuitThreshold =
valueObject.getFieldAsLong(JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD);
if (slowShortCircuitThreshold != null)
{
properties.setSlowShortCircuitThreshold(slowShortCircuitThreshold);
}
final Boolean includeExtendedResponseData = valueObject.getFieldAsBoolean(
JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA);
if (includeExtendedResponseData == null)
{
properties.setIncludeExtendedResponseData(false);
}
else
{
properties.setIncludeExtendedResponseData(includeExtendedResponseData);
}
if (strict)
{
final List unrecognizedFields =
JSONControlDecodeHelper.getControlObjectUnexpectedFields(
valueObject, JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE,
JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES,
JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED,
JSON_FIELD_INCLUDE_DEBUG_INFO,
JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES,
JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD,
JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD,
JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA);
if (! unrecognizedFields.isEmpty())
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_MATCHING_ENTRY_COUNT_RESPONSE_JSON_UNRECOGNIZED_FIELD.get(
controlObject.toSingleLineString(),
unrecognizedFields.get(0)));
}
}
return new MatchingEntryCountRequestControl(jsonControl.getCriticality(),
properties);
}
/**
* {@inheritDoc}
*/
@Override()
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("MatchingEntryCountRequestControl(isCritical=");
buffer.append(isCritical());
buffer.append(", maxCandidatesToExamine=");
buffer.append(maxCandidatesToExamine);
buffer.append(", alwaysExamineCandidates=");
buffer.append(alwaysExamineCandidates);
buffer.append(", processSearchIfUnindexed=");
buffer.append(processSearchIfUnindexed);
buffer.append(", skipResolvingExplodedIndexes=");
buffer.append(skipResolvingExplodedIndexes);
buffer.append(", fastShortCircuitThreshold=");
buffer.append(fastShortCircuitThreshold);
buffer.append(", slowShortCircuitThreshold=");
buffer.append(slowShortCircuitThreshold);
buffer.append(", includeExtendedResponseData=");
buffer.append(includeExtendedResponseData);
buffer.append(", includeDebugInfo=");
buffer.append(includeDebugInfo);
buffer.append(')');
}
}