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