001/*
002 * Copyright 2014-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2014-2022 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2014-2022 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.controls;
037
038
039
040import java.util.ArrayList;
041
042import com.unboundid.asn1.ASN1Boolean;
043import com.unboundid.asn1.ASN1Element;
044import com.unboundid.asn1.ASN1Integer;
045import com.unboundid.asn1.ASN1Long;
046import com.unboundid.asn1.ASN1OctetString;
047import com.unboundid.asn1.ASN1Sequence;
048import com.unboundid.ldap.sdk.Control;
049import com.unboundid.ldap.sdk.LDAPException;
050import com.unboundid.ldap.sdk.LDAPInterface;
051import com.unboundid.ldap.sdk.ResultCode;
052import com.unboundid.ldap.sdk.RootDSE;
053import com.unboundid.util.Debug;
054import com.unboundid.util.NotMutable;
055import com.unboundid.util.NotNull;
056import com.unboundid.util.Nullable;
057import com.unboundid.util.StaticUtils;
058import com.unboundid.util.ThreadSafety;
059import com.unboundid.util.ThreadSafetyLevel;
060import com.unboundid.util.Validator;
061
062import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
063
064
065
066/**
067 * This class provides a request control which may be included in a search
068 * request to indicate that the server should provide the number of entries that
069 * match the search criteria.  The count will be included in the search result
070 * done message, and all search result entries will be suppressed.
071 * <BR>
072 * <BLOCKQUOTE>
073 *   <B>NOTE:</B>  This class, and other classes within the
074 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
075 *   supported for use against Ping Identity, UnboundID, and
076 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
077 *   for proprietary functionality or for external specifications that are not
078 *   considered stable or mature enough to be guaranteed to work in an
079 *   interoperable way with other types of LDAP servers.
080 * </BLOCKQUOTE>
081 * <BR>
082 * Whenever possible, the server will use index information to quickly identify
083 * entries matching the criteria of the associated search request.  However, if
084 * the count is only determined using index information, then that count may
085 * include entries that would not actually be returned to the client in the
086 * course of processing that search (e.g., because the client doesn't have
087 * permission to access the entry, or because it is a special "operational"
088 * entry like an LDAP subentry, replication conflict entry, or soft-deleted
089 * entry).  Indicating that the server should always examine candidate entries
090 * will increase the length of time to obtain the matching entry count, but will
091 * ensure that the count will not include entries that would not otherwise be
092 * returned by that search.
093 * <BR><BR>
094 * Also note that this control is not compatible for use with other controls
095 * that may cause only a subset of entries to be returned, including the simple
096 * paged results control and the virtual list view control.  It is also not
097 * compatible for use with other controls that may cause the server to return
098 * more entries than those that match the search criteria, like the LDAP join
099 * control.
100 * <BR><BR>
101 * The OID for a matching entry count request control is
102 * "1.3.6.1.4.1.30221.2.5.36", and it may have a criticality of either
103 * {@code true} or {@code false}.  It must include a value with the following
104 * encoding:
105 * <PRE>
106 *   MatchingEntryCountRequest ::= SEQUENCE {
107 *        maxCandidatesToExamine           [0] INTEGER (0 .. MAX) DEFAULT 0,
108 *        alwaysExamineCandidates          [1] BOOLEAN DEFAULT FALSE,
109 *        processSearchIfUnindexed         [2] BOOLEAN DEFAULT FALSE,
110 *        includeDebugInfo                 [3] BOOLEAN DEFAULT FALSE,
111 *        skipResolvingExplodedIndexes     [4] BOOLEAN DEFAULT FALSE,
112 *        fastShortCircuitThreshold        [5] INTEGER (0 .. MAX) OPTIONAL,
113 *        slowShortCircuitThreshold        [6] INTEGER (0 .. MAX) OPTIONAL,
114 *        includeExtendedResponseData      [7] BOOLEAN DEFAULT FALSE,
115 *        ... }
116 * </PRE>
117 *
118 * @see  MatchingEntryCountResponseControl
119 */
120@NotMutable()
121@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
122public final class MatchingEntryCountRequestControl
123       extends Control
124{
125  /**
126   * The OID (1.3.6.1.4.1.30221.2.5.36) for the matching entry count request
127   * control.
128   */
129  @NotNull public static final String MATCHING_ENTRY_COUNT_REQUEST_OID =
130       "1.3.6.1.4.1.30221.2.5.36";
131
132
133
134  /**
135   * The OID (1.3.6.1.4.1.30221.2.12.7) for the supportedFeature value that a
136   * server should advertise in its root DSE if it supports returning extended
137   * information in the response control that older clients may not be able to
138   * handle.  Clients that wish to use the {@code includeExtendedResponseData}
139   * element of the request control should check the target server's root DSE
140   * to determine whether it supports this feature before requesting it because
141   * older versions of the server that do not support it may not accept a
142   * control that requests it.
143   */
144  @NotNull public static final String EXTENDED_RESPONSE_DATA_FEATURE_OID =
145       "1.3.6.1.4.1.30221.2.12.7";
146
147
148
149  /**
150   * The BER type for the element that specifies the maximum number of candidate
151   * entries to examine.
152   */
153  private static final byte TYPE_MAX_CANDIDATES_TO_EXAMINE = (byte) 0x80;
154
155
156
157  /**
158   * The BER type for the element that indicates whether always examine
159   * candidate entries to determine whether they would actually be returned to
160   * the client.
161   */
162  private static final byte TYPE_ALWAYS_EXAMINE_CANDIDATES = (byte) 0x81;
163
164
165
166  /**
167   * The BER type for the element that indicates whether to process an unindexed
168   * search to determine the number of matching entries.
169   */
170  private static final byte TYPE_PROCESS_SEARCH_IF_UNINDEXED = (byte) 0x82;
171
172
173
174  /**
175   * The BER type for the element that indicates whether to include debug
176   * information in the response.
177   */
178  private static final byte TYPE_INCLUDE_DEBUG_INFO = (byte) 0x83;
179
180
181
182  /**
183   * The BER type for the element that indicates whether to skip resolving
184   * exploded indexes if the number of matching entries is known.
185   */
186  private static final byte TYPE_SKIP_RESOLVING_EXPLODED_INDEXES = (byte) 0x84;
187
188
189
190  /**
191   * The BER type for the element that specifies the short-circuit threshold to
192   * use when performing index processing that is expected to be very fast
193   * (e.g., filter components that can be evaluated with a single index lookup,
194   * like presence, equality, and approximate match components).
195   */
196  private static final byte TYPE_FAST_SHORT_CIRCUIT_THRESHOLD = (byte) 0x85;
197
198
199
200  /**
201   * The BER type for the element that specifies the short-circuit threshold to
202   * use when evaluating filter components that are not covered by the fast
203   * short-circuit threshold.
204   */
205  private static final byte TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD = (byte) 0x86;
206
207
208
209  /**
210   * The BER type for the element that indicates whether the client wants the
211   * server to return extended information in the response, including elements
212   * that may indicate whether all of the identified candidate entries are
213   * within the scope of the search and any portion of the filter that is
214   * unindexed or unevaluated.
215   */
216  private static final byte TYPE_INCLUDE_EXTENDED_RESPONSE_DATA = (byte) 0x87;
217
218
219
220  /**
221   * The serial version UID for this serializable class.
222   */
223  private static final long serialVersionUID = 8670611963939571953L;
224
225
226
227  // Indicates whether the server should internally retrieve and examine
228  // candidate entries to determine whether they would actually be returned to
229  // the client.
230  private final boolean alwaysExamineCandidates;
231
232  // Indicates whether to include debug information in the response control.
233  private final boolean includeDebugInfo;
234
235  // Indicates whether to include extended information in the response.
236  private final boolean includeExtendedResponseData;
237
238  // Indicates whether the server should attempt to actually iterate through the
239  // entries in the backend in order to obtain the count if the search criteria
240  // is not indexed.
241  private final boolean processSearchIfUnindexed;
242
243  // Indicates whether the server should skip retrieving the entry ID set for
244  // an exploded index key if the number of matching entries is known.
245  private final boolean skipResolvingExplodedIndexes;
246
247  // The maximum number of candidate entries that should be examined if it is
248  // not possible to obtain an exact count using only information contained in
249  // the server indexes.
250  private final int maxCandidatesToExamine;
251
252  // The short-circuit threshold that the server will use when evaluating filter
253  // components that are not categorized as fast.
254  @Nullable private final Long slowShortCircuitThreshold;
255
256  // The short-circuit threshold that the server will for index processing that
257  // should be very fast.
258  @Nullable private final Long fastShortCircuitThreshold;
259
260
261
262  /**
263   * Creates a new matching entry count request control with the default
264   * settings.  The control will be critical, no candidate entries will be
265   * examined, and the search will not be processed if it is unindexed.
266   */
267  public MatchingEntryCountRequestControl()
268  {
269    this(true, 0, false, false, false);
270  }
271
272
273
274  /**
275   * Creates a new matching entry count request control with the provided
276   * information.
277   *
278   * @param  isCritical                Indicates whether this control should be
279   *                                   critical.
280   * @param  maxCandidatesToExamine    The maximum number of candidate entries
281   *                                   that the server should retrieve and
282   *                                   examine to determine whether they
283   *                                   actually match the search criteria.  If
284   *                                   the search is partially indexed and the
285   *                                   total number of candidate entries is less
286   *                                   than or equal to this value, then these
287   *                                   candidate entries will be examined to
288   *                                   determine which of them match the search
289   *                                   criteria so that an accurate count can
290   *                                   be determined.  If the search is fully
291   *                                   indexed such that the all candidate
292   *                                   entries are known to match the search
293   *                                   criteria, then the server may still
294   *                                   examine each of these entries if the
295   *                                   number of candidates is less than
296   *                                   {@code maxCandidatesToExamine} and
297   *                                   {@code alwaysExamineCandidates} is true
298   *                                   in order to allow the entry count that
299   *                                   is returned to be restricted to only
300   *                                   those entries that would actually be
301   *                                   returned to the client.  This will be
302   *                                   ignored for searches that are completely
303   *                                   unindexed.
304   *                                   <BR><BR>
305   *                                   The value for this argument must be
306   *                                   greater than or equal to zero.  If it
307   *                                   is zero, then the server will not
308   *                                   examine any entries, so a
309   *                                   partially-indexed search will only be
310   *                                   able to return a count that is an upper
311   *                                   bound, and a fully-indexed search will
312   *                                   only be able to return an unexamined
313   *                                   exact count.  If there should be no bound
314   *                                   on the number of entries to retrieve,
315   *                                   then a value of {@code Integer.MAX_VALUE}
316   *                                   may be specified.
317   * @param  alwaysExamineCandidates   Indicates whether the server should
318   *                                   always examine candidate entries to
319   *                                   determine whether they would actually
320   *                                   be returned to the client in a normal
321   *                                   search.  This will only be used for
322   *                                   fully-indexed searches in which the
323   *                                   set of matching entries is known.  If the
324   *                                   value is {@code true} and the number of
325   *                                   candidates is smaller than
326   *                                   {@code maxCandidatesToExamine}, then each
327   *                                   matching entry will be internally
328   *                                   retrieved and examined to determine
329   *                                   whether it would be returned to the
330   *                                   client based on the details of the search
331   *                                   request (e.g., whether the requester has
332   *                                   permission to access the entry, whether
333   *                                   it's an LDAP subentry, replication
334   *                                   conflict entry, soft-deleted entry, or
335   *                                   other type of entry that is normally
336   *                                   hidden) so that an exact count can be
337   *                                   returned.  If this is {@code false} or
338   *                                   the number of candidates exceeds
339   *                                   {@code maxCandidatesToExamine}, then the
340   *                                   server will only be able to return an
341   *                                   unexamined count which may include
342   *                                   entries that match the search criteria
343   *                                   but that would not normally be returned
344   *                                   to the requester.
345   * @param  processSearchIfUnindexed  Indicates whether the server should
346   *                                   attempt to determine the number of
347   *                                   matching entries if the search criteria
348   *                                   is completely unindexed.  If this is
349   *                                   {@code true} and the requester has the
350   *                                   unindexed-search privilege, then the
351   *                                   server will iterate through all entries
352   *                                   in the scope (which may take a very long
353   *                                   time to complete) in order to to
354   *                                   determine which of them match the search
355   *                                   criteria so that it can return an
356   *                                   accurate count.  If this is
357   *                                   {@code false} or the requester does not
358   *                                   have the unindexed-search privilege, then
359   *                                   the server will not spend any time
360   *                                   attempting to determine the number of
361   *                                   matching entries and will instead return
362   *                                   a matching entry count response control
363   *                                   indicating that the entry count is
364   *                                   unknown.
365   * @param  includeDebugInfo          Indicates whether the server should
366   *                                   include debug information in the response
367   *                                   that may help better understand how it
368   *                                   arrived at the result.  If any debug
369   *                                   information is returned, it will be in
370   *                                   the form of human-readable text that is
371   *                                   not intended to be machine-parsable.
372   */
373  public MatchingEntryCountRequestControl(final boolean isCritical,
374              final int maxCandidatesToExamine,
375              final boolean alwaysExamineCandidates,
376              final boolean processSearchIfUnindexed,
377              final boolean includeDebugInfo)
378  {
379    this(isCritical, maxCandidatesToExamine, alwaysExamineCandidates,
380         processSearchIfUnindexed, false, null, null, includeDebugInfo);
381  }
382
383
384
385  /**
386   * Creates a new matching entry count request control with the provided
387   * information.
388   *
389   * @param  isCritical                    Indicates whether this control should
390   *                                       be critical.
391   * @param  maxCandidatesToExamine        The maximum number of candidate
392   *                                       entries that the server should
393   *                                       retrieve and examine to determine
394   *                                       whether they actually match the
395   *                                       search criteria.  If the search is
396   *                                       partially indexed and the total
397   *                                       number of candidate entries is less
398   *                                       than or equal to this value, then
399   *                                       these candidate entries will be
400   *                                       examined to determine which of them
401   *                                       match the search criteria so that an
402   *                                       accurate count can be determined.  If
403   *                                       the search is fully indexed such that
404   *                                       the all candidate entries are known
405   *                                       to match the search criteria, then
406   *                                       the server may still examine each of
407   *                                       these entries if the number of
408   *                                       candidates is less than
409   *                                       {@code maxCandidatesToExamine} and
410   *                                       {@code alwaysExamineCandidates} is
411   *                                       {@code true} in order to allow the
412   *                                       entry count that is returned to be
413   *                                       restricted to only those entries that
414   *                                       would actually be returned to the
415   *                                       client.  This will be ignored for
416   *                                       searches that are completely
417   *                                       unindexed.
418   *                                       <BR><BR>
419   *                                       The value for this argument must be
420   *                                       greater than or equal to zero.  If it
421   *                                       is zero, then the server will not
422   *                                       examine any entries, so a
423   *                                       partially-indexed search will only be
424   *                                       able to return a count that is an
425   *                                       upper bound, and a fully-indexed
426   *                                       search will only be able to return an
427   *                                       unexamined exact count.  If there
428   *                                       should be no bound on the number of
429   *                                       entries to retrieve, then a value of
430   *                                       {@code Integer.MAX_VALUE} may be
431   *                                       specified.
432   * @param  alwaysExamineCandidates       Indicates whether the server should
433   *                                       always examine candidate entries to
434   *                                       determine whether they would actually
435   *                                       be returned to the client in a normal
436   *                                       search.  This will only be used for
437   *                                       fully-indexed searches in which the
438   *                                       set of matching entries is known.  If
439   *                                       the value is {@code true} and the
440   *                                       number of candidates is smaller than
441   *                                       {@code maxCandidatesToExamine}, then
442   *                                       each matching entry will be
443   *                                       internally retrieved and examined to
444   *                                       determine whether it would be
445   *                                       returned to the client based on the
446   *                                       details of the search request (e.g.,
447   *                                       whether the requester has permission
448   *                                       to access the entry, whether it's an
449   *                                       LDAP subentry, replication conflict
450   *                                       entry, soft-deleted entry, or other
451   *                                       type of entry that is normally
452   *                                       hidden, etc.) so that an exact count
453   *                                       can be returned.  If this is
454   *                                       {@code false} or the number of
455   *                                       candidates exceeds
456   *                                       {@code maxCandidatesToExamine}, then
457   *                                       the server will only be able to
458   *                                       return an unexamined count which may
459   *                                       include entries that match the search
460   *                                       criteria but that would not normally
461   *                                       be returned to the requester.
462   * @param  processSearchIfUnindexed      Indicates whether the server should
463   *                                       attempt to determine the number of
464   *                                       matching entries if the search
465   *                                       criteria is completely unindexed.  If
466   *                                       this is {@code true} and the
467   *                                       requester has the unindexed-search
468   *                                       privilege, then the server will
469   *                                       iterate through all entries in the
470   *                                       scope (which may take a very long
471   *                                       time to complete) in order to to
472   *                                       determine which of them match the
473   *                                       search criteria so that it can return
474   *                                       an accurate count.  If this is
475   *                                       {@code false} or the requester does
476   *                                       not have the unindexed-search
477   *                                       privilege, then the server will not
478   *                                       spend any time attempting to
479   *                                       determine the number of matching
480   *                                       entries and will instead return a
481   *                                       matching entry count response control
482   *                                       indicating that the entry count is
483   *                                       unknown.
484   * @param  skipResolvingExplodedIndexes  Indicates whether the server should
485   *                                       skip the effort of actually
486   *                                       retrieving the candidate entry IDs
487   *                                       for exploded index keys in which the
488   *                                       number of matching entries is known.
489   *                                       Skipping the process of retrieving
490   *                                       the candidate entry IDs can allow the
491   *                                       server to more quickly estimate the
492   *                                       matching entry count, but the
493   *                                       resulting estimate may be less
494   *                                       accurate.
495   * @param  fastShortCircuitThreshold     Specifies the short-circuit threshold
496   *                                       that the server should use when
497   *                                       determining whether to continue with
498   *                                       index processing in an attempt to
499   *                                       further pare down a candidate set
500   *                                       that already has a defined superset
501   *                                       of the entries that actually match
502   *                                       the filter.  Short-circuiting may
503   *                                       allow the server to skip
504   *                                       potentially-costly index processing
505   *                                       and allow it to obtain the matching
506   *                                       entry count estimate faster, but the
507   *                                       resulting estimate may be less
508   *                                       accurate.  The fast short-circuit
509   *                                       threshold will be used for index
510   *                                       processing that is expected to be
511   *                                       very fast (e.g., when performing
512   *                                       index lookups for presence, equality,
513   *                                       and approximate-match components,
514   *                                       which should only require accessing a
515   *                                       single index key).  A value that is
516   *                                       less than or equal to zero indicates
517   *                                       that the server should never short
518   *                                       circuit when performing fast index
519   *                                       processing.  A value of {@code null}
520   *                                       indicates that the server should
521   *                                       determine the appropriate fast
522   *                                       short-circuit threshold to use.
523   * @param  slowShortCircuitThreshold     Specifies the short-circuit threshold
524   *                                       that the server should use when
525   *                                       determining whether to continue with
526   *                                       index processing for evaluation that
527   *                                       may be more expensive than what falls
528   *                                       into the "fast" category (e.g.,
529   *                                       substring and range filter
530   *                                       components).  A value that is less
531   *                                       than or equal to zero indicates that
532   *                                       the server should never short circuit
533   *                                       when performing slow index
534   *                                       processing.  A value of {@code null}
535   *                                       indicates that the server should
536   *                                       determine the appropriate slow
537   *                                       short-circuit threshold to use.
538   * @param  includeDebugInfo              Indicates whether the server should
539   *                                       include debug information in the
540   *                                       response that may help better
541   *                                       understand how it arrived at the
542   *                                       result.  If any debug information is
543   *                                       returned, it will be in the form of
544   *                                       human-readable text that is not
545   *                                       intended to be machine-parsable.
546   */
547  public MatchingEntryCountRequestControl(final boolean isCritical,
548              final int maxCandidatesToExamine,
549              final boolean alwaysExamineCandidates,
550              final boolean processSearchIfUnindexed,
551              final boolean skipResolvingExplodedIndexes,
552              @Nullable final Long fastShortCircuitThreshold,
553              @Nullable final Long slowShortCircuitThreshold,
554              final boolean includeDebugInfo)
555  {
556    super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical,
557         encodeValue(maxCandidatesToExamine, alwaysExamineCandidates,
558              processSearchIfUnindexed, skipResolvingExplodedIndexes,
559              fastShortCircuitThreshold, slowShortCircuitThreshold, false,
560              includeDebugInfo));
561
562    Validator.ensureTrue(maxCandidatesToExamine >= 0);
563
564    this.maxCandidatesToExamine       = maxCandidatesToExamine;
565    this.alwaysExamineCandidates      = alwaysExamineCandidates;
566    this.processSearchIfUnindexed     = processSearchIfUnindexed;
567    this.skipResolvingExplodedIndexes = skipResolvingExplodedIndexes;
568    this.includeDebugInfo             = includeDebugInfo;
569
570    if (fastShortCircuitThreshold == null)
571    {
572      this.fastShortCircuitThreshold = null;
573    }
574    else
575    {
576      this.fastShortCircuitThreshold = Math.max(0L, fastShortCircuitThreshold);
577    }
578
579    if (slowShortCircuitThreshold == null)
580    {
581      this.slowShortCircuitThreshold = null;
582    }
583    else
584    {
585      this.slowShortCircuitThreshold = Math.max(0L, slowShortCircuitThreshold);
586    }
587
588    includeExtendedResponseData = false;
589  }
590
591
592
593  /**
594   * Creates a new matching entry count request control with the provided
595   * properties.
596   *
597   * @param  isCritical  Indicates whether the control should be critical.
598   * @param  properties  The properties that should be used to create this
599   *                     matching entry count request control.  It must not be
600   *                     {@code null}.
601   */
602  public MatchingEntryCountRequestControl(final boolean isCritical,
603       @NotNull final MatchingEntryCountRequestControlProperties properties)
604  {
605    super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical,
606         encodeValue(properties.getMaxCandidatesToExamine(),
607              properties.alwaysExamineCandidates(),
608              properties.processSearchIfUnindexed(),
609              properties.skipResolvingExplodedIndexes(),
610              properties.getFastShortCircuitThreshold(),
611              properties.getSlowShortCircuitThreshold(),
612              properties.includeExtendedResponseData(),
613              properties.includeDebugInfo()));
614
615    maxCandidatesToExamine = properties.getMaxCandidatesToExamine();
616    alwaysExamineCandidates = properties.alwaysExamineCandidates();
617    processSearchIfUnindexed = properties.processSearchIfUnindexed();
618    skipResolvingExplodedIndexes = properties.skipResolvingExplodedIndexes();
619    fastShortCircuitThreshold = properties.getFastShortCircuitThreshold();
620    slowShortCircuitThreshold = properties.getSlowShortCircuitThreshold();
621    includeExtendedResponseData = properties.includeExtendedResponseData();
622    includeDebugInfo = properties.includeDebugInfo();
623  }
624
625
626
627  /**
628   * Creates a new matching entry count request control that is decoded from the
629   * provided generic control.
630   *
631   * @param  control  The control to decode as a matching entry count request
632   *                  control.
633   *
634   * @throws  LDAPException  If the provided control cannot be decoded as a
635   *                         matching entry count request control.
636   */
637  public MatchingEntryCountRequestControl(@NotNull final Control control)
638         throws LDAPException
639  {
640    super(control);
641
642    final ASN1OctetString value = control.getValue();
643    if (value == null)
644    {
645      throw new LDAPException(ResultCode.DECODING_ERROR,
646           ERR_MATCHING_ENTRY_COUNT_REQUEST_MISSING_VALUE.get());
647    }
648
649    try
650    {
651      boolean alwaysExamine    = false;
652      boolean debug            = false;
653      boolean includeExtended  = false;
654      boolean processUnindexed = false;
655      boolean skipExploded     = false;
656      int     maxCandidates    = 0;
657      Long    fastSCThreshold  = null;
658      Long    slowSCThreshold  = null;
659      final ASN1Element[] elements =
660           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
661      for (final ASN1Element e : elements)
662      {
663        switch (e.getType())
664        {
665          case TYPE_MAX_CANDIDATES_TO_EXAMINE:
666            maxCandidates = ASN1Integer.decodeAsInteger(e).intValue();
667            if (maxCandidates < 0)
668            {
669              throw new LDAPException(ResultCode.DECODING_ERROR,
670                   ERR_MATCHING_ENTRY_COUNT_REQUEST_INVALID_MAX.get());
671            }
672            break;
673
674          case TYPE_ALWAYS_EXAMINE_CANDIDATES:
675            alwaysExamine = ASN1Boolean.decodeAsBoolean(e).booleanValue();
676            break;
677
678          case TYPE_PROCESS_SEARCH_IF_UNINDEXED:
679            processUnindexed = ASN1Boolean.decodeAsBoolean(e).booleanValue();
680            break;
681
682          case TYPE_INCLUDE_DEBUG_INFO:
683            debug = ASN1Boolean.decodeAsBoolean(e).booleanValue();
684            break;
685
686          case TYPE_SKIP_RESOLVING_EXPLODED_INDEXES:
687            skipExploded = ASN1Boolean.decodeAsBoolean(e).booleanValue();
688            break;
689
690          case TYPE_FAST_SHORT_CIRCUIT_THRESHOLD:
691            fastSCThreshold =
692                 Math.max(0L, ASN1Long.decodeAsLong(e).longValue());
693            break;
694
695          case TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD:
696            slowSCThreshold =
697                 Math.max(0L, ASN1Long.decodeAsLong(e).longValue());
698            break;
699
700          case TYPE_INCLUDE_EXTENDED_RESPONSE_DATA:
701            includeExtended = ASN1Boolean.decodeAsBoolean(e).booleanValue();
702            break;
703        }
704      }
705
706      maxCandidatesToExamine       = maxCandidates;
707      alwaysExamineCandidates      = alwaysExamine;
708      processSearchIfUnindexed     = processUnindexed;
709      includeDebugInfo             = debug;
710      includeExtendedResponseData  = includeExtended;
711      skipResolvingExplodedIndexes = skipExploded;
712      fastShortCircuitThreshold    = fastSCThreshold;
713      slowShortCircuitThreshold    = slowSCThreshold;
714    }
715    catch (final LDAPException le)
716    {
717      Debug.debugException(le);
718      throw le;
719    }
720    catch (final Exception e)
721    {
722      Debug.debugException(e);
723      throw new LDAPException(ResultCode.DECODING_ERROR,
724           ERR_MATCHING_ENTRY_COUNT_REQUEST_CANNOT_DECODE.get(
725                StaticUtils.getExceptionMessage(e)),
726           e);
727    }
728  }
729
730
731
732  /**
733   * Encodes the provided information into an ASN.1 octet string suitable for
734   * use as the control value.
735   *
736   * @param  maxCandidatesToExamine        The maximum number of candidate
737   *                                       entries that the server should
738   *                                       retrieve and examine to determine
739   *                                       whether they actually match the
740   *                                       search criteria.
741   * @param  alwaysExamineCandidates       Indicates whether the server should
742   *                                       always examine candidate entries to
743   *                                       determine whether they would actually
744   *                                       be returned to the client in a normal
745   *                                       search with the same criteria.
746   * @param  processSearchIfUnindexed      Indicates whether the server should
747   *                                       attempt to determine the number of
748   *                                       matching entries if the search
749   *                                       criteria is completely unindexed.
750   * @param  skipResolvingExplodedIndexes  Indicates whether the server should
751   *                                       skip the effort of actually
752   *                                       retrieving the candidate entry IDs
753   *                                       for exploded index keys in which the
754   *                                       number of matching entries is known.
755   * @param  fastShortCircuitThreshold     Specifies the short-circuit threshold
756   *                                       that the server should use when
757   *                                       determining whether to continue with
758   *                                       index processing for fast index
759   *                                       processing.
760   * @param  slowShortCircuitThreshold     Specifies the short-circuit threshold
761   *                                       that the server should use when
762   *                                       determining whether to continue with
763   *                                       index processing for slow index
764   *                                       processing.
765   * @param  includeExtendedResponseData  Indicates whether the server may
766   *                                      include extended response data in the
767   *                                      corresponding response control.
768   * @param  includeDebugInfo              Indicates whether the server should
769   *                                       include debug information in the
770   *                                       response that may help better
771   *                                       understand how it arrived at the
772   *                                       result.
773   *
774   * @return  The ASN.1 octet string containing the encoded control value.
775   */
776  @NotNull()
777  private static ASN1OctetString encodeValue(
778                      final int maxCandidatesToExamine,
779                      final boolean alwaysExamineCandidates,
780                      final boolean processSearchIfUnindexed,
781                      final boolean skipResolvingExplodedIndexes,
782                      @Nullable final Long fastShortCircuitThreshold,
783                      @Nullable final Long slowShortCircuitThreshold,
784                      final boolean includeExtendedResponseData,
785                      final boolean includeDebugInfo)
786  {
787    final ArrayList<ASN1Element> elements = new ArrayList<>(4);
788
789    if (maxCandidatesToExamine > 0)
790    {
791      elements.add(new ASN1Integer(TYPE_MAX_CANDIDATES_TO_EXAMINE,
792           maxCandidatesToExamine));
793    }
794
795    if (alwaysExamineCandidates)
796    {
797      elements.add(new ASN1Boolean(TYPE_ALWAYS_EXAMINE_CANDIDATES, true));
798    }
799
800    if (processSearchIfUnindexed)
801    {
802      elements.add(new ASN1Boolean(TYPE_PROCESS_SEARCH_IF_UNINDEXED, true));
803    }
804
805    if (includeDebugInfo)
806    {
807      elements.add(new ASN1Boolean(TYPE_INCLUDE_DEBUG_INFO, true));
808    }
809
810    if (skipResolvingExplodedIndexes)
811    {
812      elements.add(new ASN1Boolean(TYPE_SKIP_RESOLVING_EXPLODED_INDEXES, true));
813    }
814
815    if (fastShortCircuitThreshold != null)
816    {
817      elements.add(new ASN1Long(TYPE_FAST_SHORT_CIRCUIT_THRESHOLD,
818           Math.max(0L, fastShortCircuitThreshold)));
819    }
820
821    if (slowShortCircuitThreshold != null)
822    {
823      elements.add(new ASN1Long(TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD,
824           Math.max(0L, slowShortCircuitThreshold)));
825    }
826
827    if (includeExtendedResponseData)
828    {
829      elements.add(new ASN1Boolean(TYPE_INCLUDE_EXTENDED_RESPONSE_DATA, true));
830    }
831
832    return new ASN1OctetString(new ASN1Sequence(elements).encode());
833  }
834
835
836
837  /**
838   * Retrieves the maximum number of candidate entries that should be examined
839   * in order to determine accurate count of the number of matching entries.
840   * <BR><BR>
841   * For a fully-indexed search, this property will only be used if
842   * {@link #alwaysExamineCandidates} is true.  If the number of candidate
843   * entries identified is less than the maximum number of candidates to
844   * examine, then the server will return an {@code EXAMINED_COUNT} result that
845   * indicates the number of entries matching the criteria that would actually
846   * be returned in a normal search with the same criteria.  If the number of
847   * candidate entries exceeds the maximum number of candidates to examine, then
848   * the server will return an {@code UNEXAMINED_COUNT} result that indicates
849   * the number of entries matching the search criteria but that may include
850   * entries that would not actually be returned to the client.
851   * <BR><BR>
852   * For a partially-indexed search, if the upper bound on the number of
853   * candidates is less than or equal to the maximum number of candidates to
854   * examine, then the server will internally retrieve and examine each of those
855   * candidates to determine which of them match the search criteria and would
856   * actually be returned to the client, and will then return an
857   * {@code EXAMINED_COUNT} result with that count.  If the upper bound on the
858   * number of candidates is greater than the maximum number of candidates to
859   * examine, then the server will return an {@code UPPER_BOUND} result to
860   * indicate that the exact count is not known but an upper bound is available.
861   *
862   * @return  The maximum number of candidate entries to examine in order to
863   *          determine an accurate count of the number of matching entries.
864   */
865  public int getMaxCandidatesToExamine()
866  {
867    return maxCandidatesToExamine;
868  }
869
870
871
872  /**
873   * Indicates whether the server should always examine candidate entries in
874   * fully-indexed searches to determine whether they would actually be returned
875   * to the client in a normal search with the same criteria.
876   *
877   * @return  {@code true} if the server should attempt to internally retrieve
878   *          and examine matching entries to determine whether they would
879   *          normally be returned to the client (e.g., that the client has
880   *          permission to access the entry and that it is not a
881   *          normally-hidden entry like an LDAP subentry, a replication
882   *          conflict entry, or a soft-deleted entry), or {@code false} if the
883   *          server should return an unverified count.
884   */
885  public boolean alwaysExamineCandidates()
886  {
887    return alwaysExamineCandidates;
888  }
889
890
891
892  /**
893   * Indicates whether the server should internally retrieve and examine all
894   * entries within the search scope in order to obtain an exact matching entry
895   * count for an unindexed search.  Note that this value will not be considered
896   * for completely-indexed or partially-indexed searches, nor for searches in
897   * which matching entries should be returned.
898   *
899   * @return  {@code true} if the server should internally retrieve and examine
900   *          all entries within the search scope in order to obtain an exact
901   *          matching entry count for an unindexed search, or {@code false} if
902   *          not.
903   */
904  public boolean processSearchIfUnindexed()
905  {
906    return processSearchIfUnindexed;
907  }
908
909
910
911  /**
912   * Indicates whether the server should skip the effort of actually retrieving
913   * the candidate entry IDs for exploded index keys in which the number of
914   * matching entries is known.  Skipping the process of accessing an exploded
915   * index can allow the server to more quickly arrive at the matching entry
916   * count estimate, but that estimate may be less accurate than if it had
917   * actually retrieved those candidates.
918   *
919   * @return  {@code true} if the server should skip the effort of actually
920   *          retrieving the candidate entry IDs for exploded index keys in
921   *          which the number of matching entries is known, or {@code false} if
922   *          it may retrieve candidates from an exploded index in the course of
923   *          determining the matching entry count.
924   */
925  public boolean skipResolvingExplodedIndexes()
926  {
927    return skipResolvingExplodedIndexes;
928  }
929
930
931
932  /**
933   * Retrieves the short-circuit threshold that the server should use when
934   * determining whether to continue with index processing in an attempt to
935   * further pare down a candidate set that already has a defined superset of
936   * the entries that actually match the filter.  If the number of entries in
937   * that candidate set is less than or equal to the short-circuit threshold,
938   * then the server may simply use that candidate set in the course of
939   * determining the matching entry count, even if there may be additional
940   * processing that can be performed (e.g., further filter components to
941   * evaluate) that may allow the server to pare down the results even further.
942   * Short-circuiting may allow the server to obtain the matching entry count
943   * estimate faster, but may also cause the resulting estimate to be less
944   * accurate.
945   * <BR><BR>
946   * The value returned by this method will be used for cases in which the
947   * server is performing the fastest types of index processing.  For example,
948   * this may include evaluating presence, equality, or approximate match
949   * components, which should only require retrieving a single index key to
950   * obtain the candidate set.
951   *
952   * @return  The short-circuit threshold that should be used for fast index
953   *          processing, zero if the server should not short-circuit at all
954   *          during fast index processing, or {@code null} if the server should
955   *          determine the appropriate fast short-circuit threshold to use.
956   */
957  @Nullable()
958  public Long getFastShortCircuitThreshold()
959  {
960    return fastShortCircuitThreshold;
961  }
962
963
964
965  /**
966   * Retrieves the short-circuit threshold that the server should use when
967   * determining whether to continue with index processing in an attempt to
968   * further pare down a candidate set that already has a defined superset of
969   * the entries that actually match the filter.  If the number of entries in
970   * that candidate set is less than or equal to the short-circuit threshold,
971   * then the server may simply use that candidate set in the course of
972   * determining the matching entry count, even if there may be additional
973   * processing that can be performed (e.g., further filter components to
974   * evaluate) that may allow the server to pare down the results even further.
975   * Short-circuiting may allow the server to obtain the matching entry count
976   * estimate faster, but may also cause the resulting estimate to be less
977   * accurate.
978   * <BR><BR>
979   * The value returned by this method will be used for cases in which the
980   * server is performing index processing that is not considered to be among
981   * the fastest types of processing.  For example, this may include evaluating
982   * substring and range components, as they may require retrieving many index
983   * keys to obtain the full candidate set.
984   *
985   * @return  The short-circuit threshold that should be used for slow index
986   *          processing, or zero if the server should not short-circuit at all
987   *          during slow index processing, or {@code null} if the server should
988   *          determine the appropriate slow short-circuit threshold to use.
989   */
990  @Nullable()
991  public Long getSlowShortCircuitThreshold()
992  {
993    return slowShortCircuitThreshold;
994  }
995
996
997
998  /**
999   * Indicates whether the server may include extended response data in the
1000   * corresponding response control, which may provide information like whether
1001   * all of the identified candidate entries are within the scope of the search
1002   * and any unindexed or unevaluated portion of the search filter.
1003   *
1004   * @return  {@code true} if the server may include extended response data
1005   *          in the corresponding response control, or {@code false} if not.
1006   */
1007  public boolean includeExtendedResponseData()
1008  {
1009    return includeExtendedResponseData;
1010  }
1011
1012
1013
1014  /**
1015   * Attempts to determine whether the server to which the provided connection
1016   * is established supports including extended response data in the matching
1017   * entry count response control.
1018   *
1019   * @param  connection  The connection (or connection pool or other interface)
1020   *                     to use to communicate with the server.  It must not be
1021   *                     {@code null} and must be established.
1022   *
1023   * @return  {@code true} if the server reports that supports including
1024   *          extended response data in the matching entry count response
1025   *          control, or {@code false} if it does not indicate that it is
1026   *          supported.
1027   *
1028   * @throws  LDAPException  If a problem occurs while attempting to communicate
1029   *                         with the server.
1030   */
1031  public static boolean serverSupportsExtendedResponseData(
1032              @NotNull final LDAPInterface connection)
1033         throws LDAPException
1034  {
1035    final RootDSE rootDSE = connection.getRootDSE();
1036    return ((rootDSE != null) && serverSupportsExtendedResponseData(rootDSE));
1037  }
1038
1039
1040
1041  /**
1042   * Determines whether the provided root DSE indicates that the associated
1043   * server supports including extended response data in the matching entry
1044   * count response control.
1045   *
1046   * @param  rootDSE  The root DSE retrieved from the server for which to make
1047   *                  the determination.  It must not be {@code null}.
1048   *
1049   * @return  {@code true} if the root DSE indicates that supports including
1050   *          extended response data in the matching entry count response
1051   *          control, or {@code false} if not.
1052   */
1053  public static boolean serverSupportsExtendedResponseData(
1054              @NotNull final RootDSE rootDSE)
1055  {
1056    return rootDSE.supportsFeature(EXTENDED_RESPONSE_DATA_FEATURE_OID);
1057  }
1058
1059
1060
1061  /**
1062   * Indicates whether the server should include debug information in the
1063   * response control that provides additional information about how the server
1064   * arrived at the result.  If debug information is to be provided, it will be
1065   * in a human-readable rather than machine-parsable form.
1066   *
1067   * @return  {@code true} if the server should include debug information in
1068   *          the response control, or {@code false} if not.
1069   */
1070  public boolean includeDebugInfo()
1071  {
1072    return includeDebugInfo;
1073  }
1074
1075
1076
1077  /**
1078   * {@inheritDoc}
1079   */
1080  @Override()
1081  @NotNull()
1082  public String getControlName()
1083  {
1084    return INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get();
1085  }
1086
1087
1088
1089  /**
1090   * {@inheritDoc}
1091   */
1092  @Override()
1093  public void toString(@NotNull final StringBuilder buffer)
1094  {
1095    buffer.append("MatchingEntryCountRequestControl(isCritical=");
1096    buffer.append(isCritical());
1097    buffer.append(", maxCandidatesToExamine=");
1098    buffer.append(maxCandidatesToExamine);
1099    buffer.append(", alwaysExamineCandidates=");
1100    buffer.append(alwaysExamineCandidates);
1101    buffer.append(", processSearchIfUnindexed=");
1102    buffer.append(processSearchIfUnindexed);
1103    buffer.append(", skipResolvingExplodedIndexes=");
1104    buffer.append(skipResolvingExplodedIndexes);
1105    buffer.append(", fastShortCircuitThreshold=");
1106    buffer.append(fastShortCircuitThreshold);
1107    buffer.append(", slowShortCircuitThreshold=");
1108    buffer.append(slowShortCircuitThreshold);
1109    buffer.append(", includeExtendedResponseData=");
1110    buffer.append(includeExtendedResponseData);
1111    buffer.append(", includeDebugInfo=");
1112    buffer.append(includeDebugInfo);
1113    buffer.append(')');
1114  }
1115}