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