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