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