001/* 002 * Copyright 2014-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2014-2024 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-2024 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; 041import java.util.LinkedHashMap; 042import java.util.List; 043import java.util.Map; 044 045import com.unboundid.asn1.ASN1Boolean; 046import com.unboundid.asn1.ASN1Element; 047import com.unboundid.asn1.ASN1Integer; 048import com.unboundid.asn1.ASN1Long; 049import com.unboundid.asn1.ASN1OctetString; 050import com.unboundid.asn1.ASN1Sequence; 051import com.unboundid.ldap.sdk.Control; 052import com.unboundid.ldap.sdk.JSONControlDecodeHelper; 053import com.unboundid.ldap.sdk.LDAPException; 054import com.unboundid.ldap.sdk.LDAPInterface; 055import com.unboundid.ldap.sdk.ResultCode; 056import com.unboundid.ldap.sdk.RootDSE; 057import com.unboundid.util.Debug; 058import com.unboundid.util.NotMutable; 059import com.unboundid.util.NotNull; 060import com.unboundid.util.Nullable; 061import com.unboundid.util.StaticUtils; 062import com.unboundid.util.ThreadSafety; 063import com.unboundid.util.ThreadSafetyLevel; 064import com.unboundid.util.Validator; 065import com.unboundid.util.json.JSONBoolean; 066import com.unboundid.util.json.JSONField; 067import com.unboundid.util.json.JSONNumber; 068import com.unboundid.util.json.JSONObject; 069import com.unboundid.util.json.JSONValue; 070 071import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 072 073 074 075/** 076 * This class provides a request control which may be included in a search 077 * request to indicate that the server should provide the number of entries that 078 * match the search criteria. The count will be included in the search result 079 * done message, and all search result entries will be suppressed. 080 * <BR> 081 * <BLOCKQUOTE> 082 * <B>NOTE:</B> This class, and other classes within the 083 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 084 * supported for use against Ping Identity, UnboundID, and 085 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 086 * for proprietary functionality or for external specifications that are not 087 * considered stable or mature enough to be guaranteed to work in an 088 * interoperable way with other types of LDAP servers. 089 * </BLOCKQUOTE> 090 * <BR> 091 * Whenever possible, the server will use index information to quickly identify 092 * entries matching the criteria of the associated search request. However, if 093 * the count is only determined using index information, then that count may 094 * include entries that would not actually be returned to the client in the 095 * course of processing that search (e.g., because the client doesn't have 096 * permission to access the entry, or because it is a special "operational" 097 * entry like an LDAP subentry, replication conflict entry, or soft-deleted 098 * entry). Indicating that the server should always examine candidate entries 099 * will increase the length of time to obtain the matching entry count, but will 100 * ensure that the count will not include entries that would not otherwise be 101 * returned by that search. 102 * <BR><BR> 103 * Also note that this control is not compatible for use with other controls 104 * that may cause only a subset of entries to be returned, including the simple 105 * paged results control and the virtual list view control. It is also not 106 * compatible for use with other controls that may cause the server to return 107 * more entries than those that match the search criteria, like the LDAP join 108 * control. 109 * <BR><BR> 110 * The OID for a matching entry count request control is 111 * "1.3.6.1.4.1.30221.2.5.36", and it may have a criticality of either 112 * {@code true} or {@code false}. It must include a value with the following 113 * encoding: 114 * <PRE> 115 * MatchingEntryCountRequest ::= SEQUENCE { 116 * maxCandidatesToExamine [0] INTEGER (0 .. MAX) DEFAULT 0, 117 * alwaysExamineCandidates [1] BOOLEAN DEFAULT FALSE, 118 * processSearchIfUnindexed [2] BOOLEAN DEFAULT FALSE, 119 * includeDebugInfo [3] BOOLEAN DEFAULT FALSE, 120 * skipResolvingExplodedIndexes [4] BOOLEAN DEFAULT FALSE, 121 * fastShortCircuitThreshold [5] INTEGER (0 .. MAX) OPTIONAL, 122 * slowShortCircuitThreshold [6] INTEGER (0 .. MAX) OPTIONAL, 123 * includeExtendedResponseData [7] BOOLEAN DEFAULT FALSE, 124 * ... } 125 * </PRE> 126 * 127 * @see MatchingEntryCountResponseControl 128 */ 129@NotMutable() 130@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 131public final class MatchingEntryCountRequestControl 132 extends Control 133{ 134 /** 135 * The OID (1.3.6.1.4.1.30221.2.5.36) for the matching entry count request 136 * control. 137 */ 138 @NotNull public static final String MATCHING_ENTRY_COUNT_REQUEST_OID = 139 "1.3.6.1.4.1.30221.2.5.36"; 140 141 142 143 /** 144 * The OID (1.3.6.1.4.1.30221.2.12.7) for the supportedFeature value that a 145 * server should advertise in its root DSE if it supports returning extended 146 * information in the response control that older clients may not be able to 147 * handle. Clients that wish to use the {@code includeExtendedResponseData} 148 * element of the request control should check the target server's root DSE 149 * to determine whether it supports this feature before requesting it because 150 * older versions of the server that do not support it may not accept a 151 * control that requests it. 152 */ 153 @NotNull public static final String EXTENDED_RESPONSE_DATA_FEATURE_OID = 154 "1.3.6.1.4.1.30221.2.12.7"; 155 156 157 158 /** 159 * The BER type for the element that specifies the maximum number of candidate 160 * entries to examine. 161 */ 162 private static final byte TYPE_MAX_CANDIDATES_TO_EXAMINE = (byte) 0x80; 163 164 165 166 /** 167 * The BER type for the element that indicates whether always examine 168 * candidate entries to determine whether they would actually be returned to 169 * the client. 170 */ 171 private static final byte TYPE_ALWAYS_EXAMINE_CANDIDATES = (byte) 0x81; 172 173 174 175 /** 176 * The BER type for the element that indicates whether to process an unindexed 177 * search to determine the number of matching entries. 178 */ 179 private static final byte TYPE_PROCESS_SEARCH_IF_UNINDEXED = (byte) 0x82; 180 181 182 183 /** 184 * The BER type for the element that indicates whether to include debug 185 * information in the response. 186 */ 187 private static final byte TYPE_INCLUDE_DEBUG_INFO = (byte) 0x83; 188 189 190 191 /** 192 * The BER type for the element that indicates whether to skip resolving 193 * exploded indexes if the number of matching entries is known. 194 */ 195 private static final byte TYPE_SKIP_RESOLVING_EXPLODED_INDEXES = (byte) 0x84; 196 197 198 199 /** 200 * The BER type for the element that specifies the short-circuit threshold to 201 * use when performing index processing that is expected to be very fast 202 * (e.g., filter components that can be evaluated with a single index lookup, 203 * like presence, equality, and approximate match components). 204 */ 205 private static final byte TYPE_FAST_SHORT_CIRCUIT_THRESHOLD = (byte) 0x85; 206 207 208 209 /** 210 * The BER type for the element that specifies the short-circuit threshold to 211 * use when evaluating filter components that are not covered by the fast 212 * short-circuit threshold. 213 */ 214 private static final byte TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD = (byte) 0x86; 215 216 217 218 /** 219 * The BER type for the element that indicates whether the client wants the 220 * server to return extended information in the response, including elements 221 * that may indicate whether all of the identified candidate entries are 222 * within the scope of the search and any portion of the filter that is 223 * unindexed or unevaluated. 224 */ 225 private static final byte TYPE_INCLUDE_EXTENDED_RESPONSE_DATA = (byte) 0x87; 226 227 228 229 /** 230 * The name of the field used to hold the always examine candidates flag in 231 * the JSON representation of this control. 232 */ 233 @NotNull private static final String JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES = 234 "always-examine-candidates"; 235 236 237 238 /** 239 * The name of the field used to hold the fast short-circuit threshold in the 240 * JSON representation of this control. 241 */ 242 @NotNull private static final String JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD = 243 "fast-short-circuit-threshold"; 244 245 246 247 /** 248 * The name of the field used to hold the include debug info flag in the JSON 249 * representation of this control. 250 */ 251 @NotNull private static final String JSON_FIELD_INCLUDE_DEBUG_INFO = 252 "include-debug-info"; 253 254 255 256 /** 257 * The name of the field used to hold the include extended response data flag 258 * in the JSON representation of this control. 259 */ 260 @NotNull private static final String 261 JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA = 262 "include-extended-response-data"; 263 264 265 266 /** 267 * The name of the field used to hold the maximum candidates to examine in the 268 * JSON representation of this control. 269 */ 270 @NotNull private static final String 271 JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE = 272 "maximum-candidates-to-examine"; 273 274 275 276 /** 277 * The name of the field used to hold the process search if unindexed flag in 278 * the JSON representation of this control. 279 */ 280 @NotNull private static final String JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED = 281 "process-search-if-unindexed"; 282 283 284 285 /** 286 * The name of the field used to hold the skip resolving exploded indexes flag 287 * in the JSON representation of this control. 288 */ 289 @NotNull private static final String 290 JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES = 291 "skip-resolving-exploded-indexes"; 292 293 294 295 /** 296 * The name of the field used to hold the slow short-circuit threshold in the 297 * JSON representation of this control. 298 */ 299 @NotNull private static final String JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD = 300 "slow-short-circuit-threshold"; 301 302 303 304 /** 305 * The serial version UID for this serializable class. 306 */ 307 private static final long serialVersionUID = 8670611963939571953L; 308 309 310 311 // Indicates whether the server should internally retrieve and examine 312 // candidate entries to determine whether they would actually be returned to 313 // the client. 314 private final boolean alwaysExamineCandidates; 315 316 // Indicates whether to include debug information in the response control. 317 private final boolean includeDebugInfo; 318 319 // Indicates whether to include extended information in the response. 320 private final boolean includeExtendedResponseData; 321 322 // Indicates whether the server should attempt to actually iterate through the 323 // entries in the backend in order to obtain the count if the search criteria 324 // is not indexed. 325 private final boolean processSearchIfUnindexed; 326 327 // Indicates whether the server should skip retrieving the entry ID set for 328 // an exploded index key if the number of matching entries is known. 329 private final boolean skipResolvingExplodedIndexes; 330 331 // The maximum number of candidate entries that should be examined if it is 332 // not possible to obtain an exact count using only information contained in 333 // the server indexes. 334 private final int maxCandidatesToExamine; 335 336 // The short-circuit threshold that the server will use when evaluating filter 337 // components that are not categorized as fast. 338 @Nullable private final Long slowShortCircuitThreshold; 339 340 // The short-circuit threshold that the server will for index processing that 341 // should be very fast. 342 @Nullable private final Long fastShortCircuitThreshold; 343 344 345 346 /** 347 * Creates a new matching entry count request control with the default 348 * settings. The control will be critical, no candidate entries will be 349 * examined, and the search will not be processed if it is unindexed. 350 */ 351 public MatchingEntryCountRequestControl() 352 { 353 this(true, 0, false, false, false); 354 } 355 356 357 358 /** 359 * Creates a new matching entry count request control with the provided 360 * information. 361 * 362 * @param isCritical Indicates whether this control should be 363 * critical. 364 * @param maxCandidatesToExamine The maximum number of candidate entries 365 * that the server should retrieve and 366 * examine to determine whether they 367 * actually match the search criteria. If 368 * the search is partially indexed and the 369 * total number of candidate entries is less 370 * than or equal to this value, then these 371 * candidate entries will be examined to 372 * determine which of them match the search 373 * criteria so that an accurate count can 374 * be determined. If the search is fully 375 * indexed such that the all candidate 376 * entries are known to match the search 377 * criteria, then the server may still 378 * examine each of these entries if the 379 * number of candidates is less than 380 * {@code maxCandidatesToExamine} and 381 * {@code alwaysExamineCandidates} is true 382 * in order to allow the entry count that 383 * is returned to be restricted to only 384 * those entries that would actually be 385 * returned to the client. This will be 386 * ignored for searches that are completely 387 * unindexed. 388 * <BR><BR> 389 * The value for this argument must be 390 * greater than or equal to zero. If it 391 * is zero, then the server will not 392 * examine any entries, so a 393 * partially-indexed search will only be 394 * able to return a count that is an upper 395 * bound, and a fully-indexed search will 396 * only be able to return an unexamined 397 * exact count. If there should be no bound 398 * on the number of entries to retrieve, 399 * then a value of {@code Integer.MAX_VALUE} 400 * may be specified. 401 * @param alwaysExamineCandidates Indicates whether the server should 402 * always examine candidate entries to 403 * determine whether they would actually 404 * be returned to the client in a normal 405 * search. This will only be used for 406 * fully-indexed searches in which the 407 * set of matching entries is known. If the 408 * value is {@code true} and the number of 409 * candidates is smaller than 410 * {@code maxCandidatesToExamine}, then each 411 * matching entry will be internally 412 * retrieved and examined to determine 413 * whether it would be returned to the 414 * client based on the details of the search 415 * request (e.g., whether the requester has 416 * permission to access the entry, whether 417 * it's an LDAP subentry, replication 418 * conflict entry, soft-deleted entry, or 419 * other type of entry that is normally 420 * hidden) so that an exact count can be 421 * returned. If this is {@code false} or 422 * the number of candidates exceeds 423 * {@code maxCandidatesToExamine}, then the 424 * server will only be able to return an 425 * unexamined count which may include 426 * entries that match the search criteria 427 * but that would not normally be returned 428 * to the requester. 429 * @param processSearchIfUnindexed Indicates whether the server should 430 * attempt to determine the number of 431 * matching entries if the search criteria 432 * is completely unindexed. If this is 433 * {@code true} and the requester has the 434 * unindexed-search privilege, then the 435 * server will iterate through all entries 436 * in the scope (which may take a very long 437 * time to complete) in order to to 438 * determine which of them match the search 439 * criteria so that it can return an 440 * accurate count. If this is 441 * {@code false} or the requester does not 442 * have the unindexed-search privilege, then 443 * the server will not spend any time 444 * attempting to determine the number of 445 * matching entries and will instead return 446 * a matching entry count response control 447 * indicating that the entry count is 448 * unknown. 449 * @param includeDebugInfo Indicates whether the server should 450 * include debug information in the response 451 * that may help better understand how it 452 * arrived at the result. If any debug 453 * information is returned, it will be in 454 * the form of human-readable text that is 455 * not intended to be machine-parsable. 456 */ 457 public MatchingEntryCountRequestControl(final boolean isCritical, 458 final int maxCandidatesToExamine, 459 final boolean alwaysExamineCandidates, 460 final boolean processSearchIfUnindexed, 461 final boolean includeDebugInfo) 462 { 463 this(isCritical, maxCandidatesToExamine, alwaysExamineCandidates, 464 processSearchIfUnindexed, false, null, null, includeDebugInfo); 465 } 466 467 468 469 /** 470 * Creates a new matching entry count request control with the provided 471 * information. 472 * 473 * @param isCritical Indicates whether this control should 474 * be critical. 475 * @param maxCandidatesToExamine The maximum number of candidate 476 * entries that the server should 477 * retrieve and examine to determine 478 * whether they actually match the 479 * search criteria. If the search is 480 * partially indexed and the total 481 * number of candidate entries is less 482 * than or equal to this value, then 483 * these candidate entries will be 484 * examined to determine which of them 485 * match the search criteria so that an 486 * accurate count can be determined. If 487 * the search is fully indexed such that 488 * the all candidate entries are known 489 * to match the search criteria, then 490 * the server may still examine each of 491 * these entries if the number of 492 * candidates is less than 493 * {@code maxCandidatesToExamine} and 494 * {@code alwaysExamineCandidates} is 495 * {@code true} in order to allow the 496 * entry count that is returned to be 497 * restricted to only those entries that 498 * would actually be returned to the 499 * client. This will be ignored for 500 * searches that are completely 501 * unindexed. 502 * <BR><BR> 503 * The value for this argument must be 504 * greater than or equal to zero. If it 505 * is zero, then the server will not 506 * examine any entries, so a 507 * partially-indexed search will only be 508 * able to return a count that is an 509 * upper bound, and a fully-indexed 510 * search will only be able to return an 511 * unexamined exact count. If there 512 * should be no bound on the number of 513 * entries to retrieve, then a value of 514 * {@code Integer.MAX_VALUE} may be 515 * specified. 516 * @param alwaysExamineCandidates Indicates whether the server should 517 * always examine candidate entries to 518 * determine whether they would actually 519 * be returned to the client in a normal 520 * search. This will only be used for 521 * fully-indexed searches in which the 522 * set of matching entries is known. If 523 * the value is {@code true} and the 524 * number of candidates is smaller than 525 * {@code maxCandidatesToExamine}, then 526 * each matching entry will be 527 * internally retrieved and examined to 528 * determine whether it would be 529 * returned to the client based on the 530 * details of the search request (e.g., 531 * whether the requester has permission 532 * to access the entry, whether it's an 533 * LDAP subentry, replication conflict 534 * entry, soft-deleted entry, or other 535 * type of entry that is normally 536 * hidden, etc.) so that an exact count 537 * can be returned. If this is 538 * {@code false} or the number of 539 * candidates exceeds 540 * {@code maxCandidatesToExamine}, then 541 * the server will only be able to 542 * return an unexamined count which may 543 * include entries that match the search 544 * criteria but that would not normally 545 * be returned to the requester. 546 * @param processSearchIfUnindexed Indicates whether the server should 547 * attempt to determine the number of 548 * matching entries if the search 549 * criteria is completely unindexed. If 550 * this is {@code true} and the 551 * requester has the unindexed-search 552 * privilege, then the server will 553 * iterate through all entries in the 554 * scope (which may take a very long 555 * time to complete) in order to to 556 * determine which of them match the 557 * search criteria so that it can return 558 * an accurate count. If this is 559 * {@code false} or the requester does 560 * not have the unindexed-search 561 * privilege, then the server will not 562 * spend any time attempting to 563 * determine the number of matching 564 * entries and will instead return a 565 * matching entry count response control 566 * indicating that the entry count is 567 * unknown. 568 * @param skipResolvingExplodedIndexes Indicates whether the server should 569 * skip the effort of actually 570 * retrieving the candidate entry IDs 571 * for exploded index keys in which the 572 * number of matching entries is known. 573 * Skipping the process of retrieving 574 * the candidate entry IDs can allow the 575 * server to more quickly estimate the 576 * matching entry count, but the 577 * resulting estimate may be less 578 * accurate. 579 * @param fastShortCircuitThreshold Specifies the short-circuit threshold 580 * that the server should use when 581 * determining whether to continue with 582 * index processing in an attempt to 583 * further pare down a candidate set 584 * that already has a defined superset 585 * of the entries that actually match 586 * the filter. Short-circuiting may 587 * allow the server to skip 588 * potentially-costly index processing 589 * and allow it to obtain the matching 590 * entry count estimate faster, but the 591 * resulting estimate may be less 592 * accurate. The fast short-circuit 593 * threshold will be used for index 594 * processing that is expected to be 595 * very fast (e.g., when performing 596 * index lookups for presence, equality, 597 * and approximate-match components, 598 * which should only require accessing a 599 * single index key). A value that is 600 * less than or equal to zero indicates 601 * that the server should never short 602 * circuit when performing fast index 603 * processing. A value of {@code null} 604 * indicates that the server should 605 * determine the appropriate fast 606 * short-circuit threshold to use. 607 * @param slowShortCircuitThreshold Specifies the short-circuit threshold 608 * that the server should use when 609 * determining whether to continue with 610 * index processing for evaluation that 611 * may be more expensive than what falls 612 * into the "fast" category (e.g., 613 * substring and range filter 614 * components). A value that is less 615 * than or equal to zero indicates that 616 * the server should never short circuit 617 * when performing slow index 618 * processing. A value of {@code null} 619 * indicates that the server should 620 * determine the appropriate slow 621 * short-circuit threshold to use. 622 * @param includeDebugInfo Indicates whether the server should 623 * include debug information in the 624 * response that may help better 625 * understand how it arrived at the 626 * result. If any debug information is 627 * returned, it will be in the form of 628 * human-readable text that is not 629 * intended to be machine-parsable. 630 */ 631 public MatchingEntryCountRequestControl(final boolean isCritical, 632 final int maxCandidatesToExamine, 633 final boolean alwaysExamineCandidates, 634 final boolean processSearchIfUnindexed, 635 final boolean skipResolvingExplodedIndexes, 636 @Nullable final Long fastShortCircuitThreshold, 637 @Nullable final Long slowShortCircuitThreshold, 638 final boolean includeDebugInfo) 639 { 640 super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical, 641 encodeValue(maxCandidatesToExamine, alwaysExamineCandidates, 642 processSearchIfUnindexed, skipResolvingExplodedIndexes, 643 fastShortCircuitThreshold, slowShortCircuitThreshold, false, 644 includeDebugInfo)); 645 646 Validator.ensureTrue(maxCandidatesToExamine >= 0); 647 648 this.maxCandidatesToExamine = maxCandidatesToExamine; 649 this.alwaysExamineCandidates = alwaysExamineCandidates; 650 this.processSearchIfUnindexed = processSearchIfUnindexed; 651 this.skipResolvingExplodedIndexes = skipResolvingExplodedIndexes; 652 this.includeDebugInfo = includeDebugInfo; 653 654 if (fastShortCircuitThreshold == null) 655 { 656 this.fastShortCircuitThreshold = null; 657 } 658 else 659 { 660 this.fastShortCircuitThreshold = Math.max(0L, fastShortCircuitThreshold); 661 } 662 663 if (slowShortCircuitThreshold == null) 664 { 665 this.slowShortCircuitThreshold = null; 666 } 667 else 668 { 669 this.slowShortCircuitThreshold = Math.max(0L, slowShortCircuitThreshold); 670 } 671 672 includeExtendedResponseData = false; 673 } 674 675 676 677 /** 678 * Creates a new matching entry count request control with the provided 679 * properties. 680 * 681 * @param isCritical Indicates whether the control should be critical. 682 * @param properties The properties that should be used to create this 683 * matching entry count request control. It must not be 684 * {@code null}. 685 */ 686 public MatchingEntryCountRequestControl(final boolean isCritical, 687 @NotNull final MatchingEntryCountRequestControlProperties properties) 688 { 689 super(MATCHING_ENTRY_COUNT_REQUEST_OID, isCritical, 690 encodeValue(properties.getMaxCandidatesToExamine(), 691 properties.alwaysExamineCandidates(), 692 properties.processSearchIfUnindexed(), 693 properties.skipResolvingExplodedIndexes(), 694 properties.getFastShortCircuitThreshold(), 695 properties.getSlowShortCircuitThreshold(), 696 properties.includeExtendedResponseData(), 697 properties.includeDebugInfo())); 698 699 maxCandidatesToExamine = properties.getMaxCandidatesToExamine(); 700 alwaysExamineCandidates = properties.alwaysExamineCandidates(); 701 processSearchIfUnindexed = properties.processSearchIfUnindexed(); 702 skipResolvingExplodedIndexes = properties.skipResolvingExplodedIndexes(); 703 fastShortCircuitThreshold = properties.getFastShortCircuitThreshold(); 704 slowShortCircuitThreshold = properties.getSlowShortCircuitThreshold(); 705 includeExtendedResponseData = properties.includeExtendedResponseData(); 706 includeDebugInfo = properties.includeDebugInfo(); 707 } 708 709 710 711 /** 712 * Creates a new matching entry count request control that is decoded from the 713 * provided generic control. 714 * 715 * @param control The control to decode as a matching entry count request 716 * control. 717 * 718 * @throws LDAPException If the provided control cannot be decoded as a 719 * matching entry count request control. 720 */ 721 public MatchingEntryCountRequestControl(@NotNull final Control control) 722 throws LDAPException 723 { 724 super(control); 725 726 final ASN1OctetString value = control.getValue(); 727 if (value == null) 728 { 729 throw new LDAPException(ResultCode.DECODING_ERROR, 730 ERR_MATCHING_ENTRY_COUNT_REQUEST_MISSING_VALUE.get()); 731 } 732 733 try 734 { 735 boolean alwaysExamine = false; 736 boolean debug = false; 737 boolean includeExtended = false; 738 boolean processUnindexed = false; 739 boolean skipExploded = false; 740 int maxCandidates = 0; 741 Long fastSCThreshold = null; 742 Long slowSCThreshold = null; 743 final ASN1Element[] elements = 744 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 745 for (final ASN1Element e : elements) 746 { 747 switch (e.getType()) 748 { 749 case TYPE_MAX_CANDIDATES_TO_EXAMINE: 750 maxCandidates = ASN1Integer.decodeAsInteger(e).intValue(); 751 if (maxCandidates < 0) 752 { 753 throw new LDAPException(ResultCode.DECODING_ERROR, 754 ERR_MATCHING_ENTRY_COUNT_REQUEST_INVALID_MAX.get()); 755 } 756 break; 757 758 case TYPE_ALWAYS_EXAMINE_CANDIDATES: 759 alwaysExamine = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 760 break; 761 762 case TYPE_PROCESS_SEARCH_IF_UNINDEXED: 763 processUnindexed = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 764 break; 765 766 case TYPE_INCLUDE_DEBUG_INFO: 767 debug = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 768 break; 769 770 case TYPE_SKIP_RESOLVING_EXPLODED_INDEXES: 771 skipExploded = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 772 break; 773 774 case TYPE_FAST_SHORT_CIRCUIT_THRESHOLD: 775 fastSCThreshold = 776 Math.max(0L, ASN1Long.decodeAsLong(e).longValue()); 777 break; 778 779 case TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD: 780 slowSCThreshold = 781 Math.max(0L, ASN1Long.decodeAsLong(e).longValue()); 782 break; 783 784 case TYPE_INCLUDE_EXTENDED_RESPONSE_DATA: 785 includeExtended = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 786 break; 787 } 788 } 789 790 maxCandidatesToExamine = maxCandidates; 791 alwaysExamineCandidates = alwaysExamine; 792 processSearchIfUnindexed = processUnindexed; 793 includeDebugInfo = debug; 794 includeExtendedResponseData = includeExtended; 795 skipResolvingExplodedIndexes = skipExploded; 796 fastShortCircuitThreshold = fastSCThreshold; 797 slowShortCircuitThreshold = slowSCThreshold; 798 } 799 catch (final LDAPException le) 800 { 801 Debug.debugException(le); 802 throw le; 803 } 804 catch (final Exception e) 805 { 806 Debug.debugException(e); 807 throw new LDAPException(ResultCode.DECODING_ERROR, 808 ERR_MATCHING_ENTRY_COUNT_REQUEST_CANNOT_DECODE.get( 809 StaticUtils.getExceptionMessage(e)), 810 e); 811 } 812 } 813 814 815 816 /** 817 * Encodes the provided information into an ASN.1 octet string suitable for 818 * use as the control value. 819 * 820 * @param maxCandidatesToExamine The maximum number of candidate 821 * entries that the server should 822 * retrieve and examine to determine 823 * whether they actually match the 824 * search criteria. 825 * @param alwaysExamineCandidates Indicates whether the server should 826 * always examine candidate entries to 827 * determine whether they would actually 828 * be returned to the client in a normal 829 * search with the same criteria. 830 * @param processSearchIfUnindexed Indicates whether the server should 831 * attempt to determine the number of 832 * matching entries if the search 833 * criteria is completely unindexed. 834 * @param skipResolvingExplodedIndexes Indicates whether the server should 835 * skip the effort of actually 836 * retrieving the candidate entry IDs 837 * for exploded index keys in which the 838 * number of matching entries is known. 839 * @param fastShortCircuitThreshold Specifies the short-circuit threshold 840 * that the server should use when 841 * determining whether to continue with 842 * index processing for fast index 843 * processing. 844 * @param slowShortCircuitThreshold Specifies the short-circuit threshold 845 * that the server should use when 846 * determining whether to continue with 847 * index processing for slow index 848 * processing. 849 * @param includeExtendedResponseData Indicates whether the server may 850 * include extended response data in the 851 * corresponding response control. 852 * @param includeDebugInfo Indicates whether the server should 853 * include debug information in the 854 * response that may help better 855 * understand how it arrived at the 856 * result. 857 * 858 * @return The ASN.1 octet string containing the encoded control value. 859 */ 860 @NotNull() 861 private static ASN1OctetString encodeValue( 862 final int maxCandidatesToExamine, 863 final boolean alwaysExamineCandidates, 864 final boolean processSearchIfUnindexed, 865 final boolean skipResolvingExplodedIndexes, 866 @Nullable final Long fastShortCircuitThreshold, 867 @Nullable final Long slowShortCircuitThreshold, 868 final boolean includeExtendedResponseData, 869 final boolean includeDebugInfo) 870 { 871 final ArrayList<ASN1Element> elements = new ArrayList<>(4); 872 873 if (maxCandidatesToExamine > 0) 874 { 875 elements.add(new ASN1Integer(TYPE_MAX_CANDIDATES_TO_EXAMINE, 876 maxCandidatesToExamine)); 877 } 878 879 if (alwaysExamineCandidates) 880 { 881 elements.add(new ASN1Boolean(TYPE_ALWAYS_EXAMINE_CANDIDATES, true)); 882 } 883 884 if (processSearchIfUnindexed) 885 { 886 elements.add(new ASN1Boolean(TYPE_PROCESS_SEARCH_IF_UNINDEXED, true)); 887 } 888 889 if (includeDebugInfo) 890 { 891 elements.add(new ASN1Boolean(TYPE_INCLUDE_DEBUG_INFO, true)); 892 } 893 894 if (skipResolvingExplodedIndexes) 895 { 896 elements.add(new ASN1Boolean(TYPE_SKIP_RESOLVING_EXPLODED_INDEXES, true)); 897 } 898 899 if (fastShortCircuitThreshold != null) 900 { 901 elements.add(new ASN1Long(TYPE_FAST_SHORT_CIRCUIT_THRESHOLD, 902 Math.max(0L, fastShortCircuitThreshold))); 903 } 904 905 if (slowShortCircuitThreshold != null) 906 { 907 elements.add(new ASN1Long(TYPE_SLOW_SHORT_CIRCUIT_THRESHOLD, 908 Math.max(0L, slowShortCircuitThreshold))); 909 } 910 911 if (includeExtendedResponseData) 912 { 913 elements.add(new ASN1Boolean(TYPE_INCLUDE_EXTENDED_RESPONSE_DATA, true)); 914 } 915 916 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 917 } 918 919 920 921 /** 922 * Retrieves the maximum number of candidate entries that should be examined 923 * in order to determine accurate count of the number of matching entries. 924 * <BR><BR> 925 * For a fully-indexed search, this property will only be used if 926 * {@link #alwaysExamineCandidates} is true. If the number of candidate 927 * entries identified is less than the maximum number of candidates to 928 * examine, then the server will return an {@code EXAMINED_COUNT} result that 929 * indicates the number of entries matching the criteria that would actually 930 * be returned in a normal search with the same criteria. If the number of 931 * candidate entries exceeds the maximum number of candidates to examine, then 932 * the server will return an {@code UNEXAMINED_COUNT} result that indicates 933 * the number of entries matching the search criteria but that may include 934 * entries that would not actually be returned to the client. 935 * <BR><BR> 936 * For a partially-indexed search, if the upper bound on the number of 937 * candidates is less than or equal to the maximum number of candidates to 938 * examine, then the server will internally retrieve and examine each of those 939 * candidates to determine which of them match the search criteria and would 940 * actually be returned to the client, and will then return an 941 * {@code EXAMINED_COUNT} result with that count. If the upper bound on the 942 * number of candidates is greater than the maximum number of candidates to 943 * examine, then the server will return an {@code UPPER_BOUND} result to 944 * indicate that the exact count is not known but an upper bound is available. 945 * 946 * @return The maximum number of candidate entries to examine in order to 947 * determine an accurate count of the number of matching entries. 948 */ 949 public int getMaxCandidatesToExamine() 950 { 951 return maxCandidatesToExamine; 952 } 953 954 955 956 /** 957 * Indicates whether the server should always examine candidate entries in 958 * fully-indexed searches to determine whether they would actually be returned 959 * to the client in a normal search with the same criteria. 960 * 961 * @return {@code true} if the server should attempt to internally retrieve 962 * and examine matching entries to determine whether they would 963 * normally be returned to the client (e.g., that the client has 964 * permission to access the entry and that it is not a 965 * normally-hidden entry like an LDAP subentry, a replication 966 * conflict entry, or a soft-deleted entry), or {@code false} if the 967 * server should return an unverified count. 968 */ 969 public boolean alwaysExamineCandidates() 970 { 971 return alwaysExamineCandidates; 972 } 973 974 975 976 /** 977 * Indicates whether the server should internally retrieve and examine all 978 * entries within the search scope in order to obtain an exact matching entry 979 * count for an unindexed search. Note that this value will not be considered 980 * for completely-indexed or partially-indexed searches, nor for searches in 981 * which matching entries should be returned. 982 * 983 * @return {@code true} if the server should internally retrieve and examine 984 * all entries within the search scope in order to obtain an exact 985 * matching entry count for an unindexed search, or {@code false} if 986 * not. 987 */ 988 public boolean processSearchIfUnindexed() 989 { 990 return processSearchIfUnindexed; 991 } 992 993 994 995 /** 996 * Indicates whether the server should skip the effort of actually retrieving 997 * the candidate entry IDs for exploded index keys in which the number of 998 * matching entries is known. Skipping the process of accessing an exploded 999 * index can allow the server to more quickly arrive at the matching entry 1000 * count estimate, but that estimate may be less accurate than if it had 1001 * actually retrieved those candidates. 1002 * 1003 * @return {@code true} if the server should skip the effort of actually 1004 * retrieving the candidate entry IDs for exploded index keys in 1005 * which the number of matching entries is known, or {@code false} if 1006 * it may retrieve candidates from an exploded index in the course of 1007 * determining the matching entry count. 1008 */ 1009 public boolean skipResolvingExplodedIndexes() 1010 { 1011 return skipResolvingExplodedIndexes; 1012 } 1013 1014 1015 1016 /** 1017 * Retrieves the short-circuit threshold that the server should use when 1018 * determining whether to continue with index processing in an attempt to 1019 * further pare down a candidate set that already has a defined superset of 1020 * the entries that actually match the filter. If the number of entries in 1021 * that candidate set is less than or equal to the short-circuit threshold, 1022 * then the server may simply use that candidate set in the course of 1023 * determining the matching entry count, even if there may be additional 1024 * processing that can be performed (e.g., further filter components to 1025 * evaluate) that may allow the server to pare down the results even further. 1026 * Short-circuiting may allow the server to obtain the matching entry count 1027 * estimate faster, but may also cause the resulting estimate to be less 1028 * accurate. 1029 * <BR><BR> 1030 * The value returned by this method will be used for cases in which the 1031 * server is performing the fastest types of index processing. For example, 1032 * this may include evaluating presence, equality, or approximate match 1033 * components, which should only require retrieving a single index key to 1034 * obtain the candidate set. 1035 * 1036 * @return The short-circuit threshold that should be used for fast index 1037 * processing, zero if the server should not short-circuit at all 1038 * during fast index processing, or {@code null} if the server should 1039 * determine the appropriate fast short-circuit threshold to use. 1040 */ 1041 @Nullable() 1042 public Long getFastShortCircuitThreshold() 1043 { 1044 return fastShortCircuitThreshold; 1045 } 1046 1047 1048 1049 /** 1050 * Retrieves the short-circuit threshold that the server should use when 1051 * determining whether to continue with index processing in an attempt to 1052 * further pare down a candidate set that already has a defined superset of 1053 * the entries that actually match the filter. If the number of entries in 1054 * that candidate set is less than or equal to the short-circuit threshold, 1055 * then the server may simply use that candidate set in the course of 1056 * determining the matching entry count, even if there may be additional 1057 * processing that can be performed (e.g., further filter components to 1058 * evaluate) that may allow the server to pare down the results even further. 1059 * Short-circuiting may allow the server to obtain the matching entry count 1060 * estimate faster, but may also cause the resulting estimate to be less 1061 * accurate. 1062 * <BR><BR> 1063 * The value returned by this method will be used for cases in which the 1064 * server is performing index processing that is not considered to be among 1065 * the fastest types of processing. For example, this may include evaluating 1066 * substring and range components, as they may require retrieving many index 1067 * keys to obtain the full candidate set. 1068 * 1069 * @return The short-circuit threshold that should be used for slow index 1070 * processing, or zero if the server should not short-circuit at all 1071 * during slow index processing, or {@code null} if the server should 1072 * determine the appropriate slow short-circuit threshold to use. 1073 */ 1074 @Nullable() 1075 public Long getSlowShortCircuitThreshold() 1076 { 1077 return slowShortCircuitThreshold; 1078 } 1079 1080 1081 1082 /** 1083 * Indicates whether the server may include extended response data in the 1084 * corresponding response control, which may provide information like whether 1085 * all of the identified candidate entries are within the scope of the search 1086 * and any unindexed or unevaluated portion of the search filter. 1087 * 1088 * @return {@code true} if the server may include extended response data 1089 * in the corresponding response control, or {@code false} if not. 1090 */ 1091 public boolean includeExtendedResponseData() 1092 { 1093 return includeExtendedResponseData; 1094 } 1095 1096 1097 1098 /** 1099 * Attempts to determine whether the server to which the provided connection 1100 * is established supports including extended response data in the matching 1101 * entry count response control. 1102 * 1103 * @param connection The connection (or connection pool or other interface) 1104 * to use to communicate with the server. It must not be 1105 * {@code null} and must be established. 1106 * 1107 * @return {@code true} if the server reports that supports including 1108 * extended response data in the matching entry count response 1109 * control, or {@code false} if it does not indicate that it is 1110 * supported. 1111 * 1112 * @throws LDAPException If a problem occurs while attempting to communicate 1113 * with the server. 1114 */ 1115 public static boolean serverSupportsExtendedResponseData( 1116 @NotNull final LDAPInterface connection) 1117 throws LDAPException 1118 { 1119 final RootDSE rootDSE = connection.getRootDSE(); 1120 return ((rootDSE != null) && serverSupportsExtendedResponseData(rootDSE)); 1121 } 1122 1123 1124 1125 /** 1126 * Determines whether the provided root DSE indicates that the associated 1127 * server supports including extended response data in the matching entry 1128 * count response control. 1129 * 1130 * @param rootDSE The root DSE retrieved from the server for which to make 1131 * the determination. It must not be {@code null}. 1132 * 1133 * @return {@code true} if the root DSE indicates that supports including 1134 * extended response data in the matching entry count response 1135 * control, or {@code false} if not. 1136 */ 1137 public static boolean serverSupportsExtendedResponseData( 1138 @NotNull final RootDSE rootDSE) 1139 { 1140 return rootDSE.supportsFeature(EXTENDED_RESPONSE_DATA_FEATURE_OID); 1141 } 1142 1143 1144 1145 /** 1146 * Indicates whether the server should include debug information in the 1147 * response control that provides additional information about how the server 1148 * arrived at the result. If debug information is to be provided, it will be 1149 * in a human-readable rather than machine-parsable form. 1150 * 1151 * @return {@code true} if the server should include debug information in 1152 * the response control, or {@code false} if not. 1153 */ 1154 public boolean includeDebugInfo() 1155 { 1156 return includeDebugInfo; 1157 } 1158 1159 1160 1161 /** 1162 * {@inheritDoc} 1163 */ 1164 @Override() 1165 @NotNull() 1166 public String getControlName() 1167 { 1168 return INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get(); 1169 } 1170 1171 1172 1173 /** 1174 * Retrieves a representation of this matching entry count request control as 1175 * a JSON object. The JSON object uses the following fields: 1176 * <UL> 1177 * <LI> 1178 * {@code oid} -- A mandatory string field whose value is the object 1179 * identifier for this control. For the matching entry count request 1180 * control, the OID is "1.3.6.1.4.1.30221.2.5.36". 1181 * </LI> 1182 * <LI> 1183 * {@code control-name} -- An optional string field whose value is a 1184 * human-readable name for this control. This field is only intended for 1185 * descriptive purposes, and when decoding a control, the {@code oid} 1186 * field should be used to identify the type of control. 1187 * </LI> 1188 * <LI> 1189 * {@code criticality} -- A mandatory Boolean field used to indicate 1190 * whether this control is considered critical. 1191 * </LI> 1192 * <LI> 1193 * {@code value-base64} -- An optional string field whose value is a 1194 * base64-encoded representation of the raw value for this matching entry 1195 * count request control. Exactly one of the {@code value-base64} and 1196 * {@code value-json} fields must be present. 1197 * </LI> 1198 * <LI> 1199 * {@code value-json} -- An optional JSON object field whose value is a 1200 * user-friendly representation of the value for this matching entry count 1201 * request control. Exactly one of the {@code value-base64} and 1202 * {@code value-json} fields must be present, and if the 1203 * {@code value-json} field is used, then it will use the following 1204 * fields: 1205 * <UL> 1206 * <LI> 1207 * {@code maximum-candidates-to-examine} -- An optional integer field 1208 * whose value indicates the maximum number of entries that the server 1209 * should retrieve and examine to determine whether they actually 1210 * match the search criteria and would be returned to the client. 1211 * </LI> 1212 * <LI> 1213 * {@code always-examine-candidates} -- An optional Boolean field that 1214 * indicates whether the server should always examine candidates to 1215 * determine whether they would actually be returned to the client, 1216 * even if the search is fully indexed and the server knows that all 1217 * candidates match the search criteria. 1218 * </LI> 1219 * <LI> 1220 * {@code process-search-if-unindexed} -- An optional Boolean field 1221 * that indicates whether the server should attempt to process the 1222 * search even if the search criteria is completely unindexed. 1223 * </LI> 1224 * <LI> 1225 * {@code include-debug-info} -- An optional Boolean field 1226 * that indicates whether the server should return debug information 1227 * in the response control about the processing it performed in the 1228 * course of determining the matching entry count estimate. 1229 * </LI> 1230 * <LI> 1231 * {@code skip-resolving-exploded-indexes} -- An optional Boolean 1232 * field that indicates whether the server should skip the step of 1233 * resolving exploded indexes in cases where the size of the ID set is 1234 * known. 1235 * </LI> 1236 * <LI> 1237 * {@code fast-short-circuit-threshold} -- An optional integer field 1238 * whose value is the short-circuit threshold that the server should 1239 * use for "fast" filter components. 1240 * </LI> 1241 * <LI> 1242 * {@code slow-short-circuit-threshold} -- An optional integer field 1243 * whose value is the short-circuit threshold that the server should 1244 * use for "slow" filter components. 1245 * </LI> 1246 * <LI> 1247 * {@code include-extended-response-data} -- An optional Boolean field 1248 * that indicates whether the server should include extended 1249 * information in the response control. 1250 * </LI> 1251 * </UL> 1252 * </LI> 1253 * </UL> 1254 * 1255 * @return A JSON object that contains a representation of this control. 1256 */ 1257 @Override() 1258 @NotNull() 1259 public JSONObject toJSONControl() 1260 { 1261 final Map<String,JSONValue> valueFields = new LinkedHashMap<>(); 1262 1263 if (maxCandidatesToExamine > 0) 1264 { 1265 valueFields.put(JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE, 1266 new JSONNumber(maxCandidatesToExamine)); 1267 } 1268 else 1269 { 1270 valueFields.put(JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE, 1271 new JSONNumber(0)); 1272 } 1273 1274 valueFields.put(JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES, 1275 new JSONBoolean(alwaysExamineCandidates)); 1276 valueFields.put(JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED, 1277 new JSONBoolean(processSearchIfUnindexed)); 1278 valueFields.put(JSON_FIELD_INCLUDE_DEBUG_INFO, 1279 new JSONBoolean(includeDebugInfo)); 1280 valueFields.put(JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES, 1281 new JSONBoolean(skipResolvingExplodedIndexes)); 1282 1283 if (fastShortCircuitThreshold != null) 1284 { 1285 valueFields.put(JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD, 1286 new JSONNumber(fastShortCircuitThreshold)); 1287 } 1288 1289 if (slowShortCircuitThreshold != null) 1290 { 1291 valueFields.put(JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD, 1292 new JSONNumber(slowShortCircuitThreshold)); 1293 } 1294 1295 valueFields.put(JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA, 1296 new JSONBoolean(includeExtendedResponseData)); 1297 1298 return new JSONObject( 1299 new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, 1300 MATCHING_ENTRY_COUNT_REQUEST_OID), 1301 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME, 1302 INFO_CONTROL_NAME_MATCHING_ENTRY_COUNT_REQUEST.get()), 1303 new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY, 1304 isCritical()), 1305 new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, 1306 new JSONObject(valueFields))); 1307 } 1308 1309 1310 1311 /** 1312 * Attempts to decode the provided object as a JSON representation of a 1313 * matching entry count request control. 1314 * 1315 * @param controlObject The JSON object to be decoded. It must not be 1316 * {@code null}. 1317 * @param strict Indicates whether to use strict mode when decoding 1318 * the provided JSON object. If this is {@code true}, 1319 * then this method will throw an exception if the 1320 * provided JSON object contains any unrecognized 1321 * fields. If this is {@code false}, then unrecognized 1322 * fields will be ignored. 1323 * 1324 * @return The matching entry count request control that was decoded from the 1325 * provided JSON object. 1326 * 1327 * @throws LDAPException If the provided JSON object cannot be parsed as a 1328 * valid matching entry count request control. 1329 */ 1330 @NotNull() 1331 public static MatchingEntryCountRequestControl decodeJSONControl( 1332 @NotNull final JSONObject controlObject, 1333 final boolean strict) 1334 throws LDAPException 1335 { 1336 final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper( 1337 controlObject, strict, true, true); 1338 1339 final ASN1OctetString rawValue = jsonControl.getRawValue(); 1340 if (rawValue != null) 1341 { 1342 return new MatchingEntryCountRequestControl(new Control( 1343 jsonControl.getOID(), jsonControl.getCriticality(), rawValue)); 1344 } 1345 1346 1347 final JSONObject valueObject = jsonControl.getValueObject(); 1348 1349 final MatchingEntryCountRequestControlProperties properties = 1350 new MatchingEntryCountRequestControlProperties(); 1351 1352 final Integer maximumCandidatesToExamine = valueObject.getFieldAsInteger( 1353 JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE); 1354 if (maximumCandidatesToExamine == null) 1355 { 1356 properties.setMaxCandidatesToExamine(0); 1357 } 1358 else 1359 { 1360 properties.setMaxCandidatesToExamine(maximumCandidatesToExamine); 1361 } 1362 1363 1364 final Boolean alwaysExamineCandidates = 1365 valueObject.getFieldAsBoolean(JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES); 1366 if (alwaysExamineCandidates == null) 1367 { 1368 properties.setAlwaysExamineCandidates(false); 1369 } 1370 else 1371 { 1372 properties.setAlwaysExamineCandidates(alwaysExamineCandidates); 1373 } 1374 1375 1376 final Boolean processSearchIfUnindexed = 1377 valueObject.getFieldAsBoolean(JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED); 1378 if (processSearchIfUnindexed == null) 1379 { 1380 properties.setProcessSearchIfUnindexed(false); 1381 } 1382 else 1383 { 1384 properties.setProcessSearchIfUnindexed(processSearchIfUnindexed); 1385 } 1386 1387 1388 final Boolean includeDebugInfo = 1389 valueObject.getFieldAsBoolean(JSON_FIELD_INCLUDE_DEBUG_INFO); 1390 if (includeDebugInfo == null) 1391 { 1392 properties.setIncludeDebugInfo(false); 1393 } 1394 else 1395 { 1396 properties.setIncludeDebugInfo(includeDebugInfo); 1397 } 1398 1399 1400 final Boolean skipResolvingExplodedIndexes = 1401 valueObject.getFieldAsBoolean( 1402 JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES); 1403 if (skipResolvingExplodedIndexes == null) 1404 { 1405 properties.setSkipResolvingExplodedIndexes(false); 1406 } 1407 else 1408 { 1409 properties.setSkipResolvingExplodedIndexes(skipResolvingExplodedIndexes); 1410 } 1411 1412 1413 final Long fastShortCircuitThreshold = 1414 valueObject.getFieldAsLong(JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD); 1415 if (fastShortCircuitThreshold != null) 1416 { 1417 properties.setFastShortCircuitThreshold(fastShortCircuitThreshold); 1418 } 1419 1420 1421 final Long slowShortCircuitThreshold = 1422 valueObject.getFieldAsLong(JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD); 1423 if (slowShortCircuitThreshold != null) 1424 { 1425 properties.setSlowShortCircuitThreshold(slowShortCircuitThreshold); 1426 } 1427 1428 1429 final Boolean includeExtendedResponseData = valueObject.getFieldAsBoolean( 1430 JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA); 1431 if (includeExtendedResponseData == null) 1432 { 1433 properties.setIncludeExtendedResponseData(false); 1434 } 1435 else 1436 { 1437 properties.setIncludeExtendedResponseData(includeExtendedResponseData); 1438 } 1439 1440 1441 if (strict) 1442 { 1443 final List<String> unrecognizedFields = 1444 JSONControlDecodeHelper.getControlObjectUnexpectedFields( 1445 valueObject, JSON_FIELD_MAXIMUM_CANDIDATES_TO_EXAMINE, 1446 JSON_FIELD_ALWAYS_EXAMINE_CANDIDATES, 1447 JSON_FIELD_PROCESS_SEARCH_IF_UNINDEXED, 1448 JSON_FIELD_INCLUDE_DEBUG_INFO, 1449 JSON_FIELD_SKIP_RESOLVING_EXPLODED_INDEXES, 1450 JSON_FIELD_FAST_SHORT_CIRCUIT_THRESHOLD, 1451 JSON_FIELD_SLOW_SHORT_CIRCUIT_THRESHOLD, 1452 JSON_FIELD_INCLUDE_EXTENDED_RESPONSE_DATA); 1453 if (! unrecognizedFields.isEmpty()) 1454 { 1455 throw new LDAPException(ResultCode.DECODING_ERROR, 1456 ERR_MATCHING_ENTRY_COUNT_RESPONSE_JSON_UNRECOGNIZED_FIELD.get( 1457 controlObject.toSingleLineString(), 1458 unrecognizedFields.get(0))); 1459 } 1460 } 1461 1462 1463 return new MatchingEntryCountRequestControl(jsonControl.getCriticality(), 1464 properties); 1465 } 1466 1467 1468 1469 /** 1470 * {@inheritDoc} 1471 */ 1472 @Override() 1473 public void toString(@NotNull final StringBuilder buffer) 1474 { 1475 buffer.append("MatchingEntryCountRequestControl(isCritical="); 1476 buffer.append(isCritical()); 1477 buffer.append(", maxCandidatesToExamine="); 1478 buffer.append(maxCandidatesToExamine); 1479 buffer.append(", alwaysExamineCandidates="); 1480 buffer.append(alwaysExamineCandidates); 1481 buffer.append(", processSearchIfUnindexed="); 1482 buffer.append(processSearchIfUnindexed); 1483 buffer.append(", skipResolvingExplodedIndexes="); 1484 buffer.append(skipResolvingExplodedIndexes); 1485 buffer.append(", fastShortCircuitThreshold="); 1486 buffer.append(fastShortCircuitThreshold); 1487 buffer.append(", slowShortCircuitThreshold="); 1488 buffer.append(slowShortCircuitThreshold); 1489 buffer.append(", includeExtendedResponseData="); 1490 buffer.append(includeExtendedResponseData); 1491 buffer.append(", includeDebugInfo="); 1492 buffer.append(includeDebugInfo); 1493 buffer.append(')'); 1494 } 1495}