001/* 002 * Copyright 2007-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-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) 2007-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.controls; 037 038 039 040import com.unboundid.asn1.ASN1Element; 041import com.unboundid.asn1.ASN1Integer; 042import com.unboundid.asn1.ASN1OctetString; 043import com.unboundid.asn1.ASN1Sequence; 044import com.unboundid.ldap.sdk.Control; 045import com.unboundid.ldap.sdk.LDAPException; 046import com.unboundid.ldap.sdk.ResultCode; 047import com.unboundid.util.Debug; 048import com.unboundid.util.NotMutable; 049import com.unboundid.util.NotNull; 050import com.unboundid.util.Nullable; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054import com.unboundid.util.Validator; 055 056import static com.unboundid.ldap.sdk.controls.ControlMessages.*; 057 058 059 060/** 061 * This class provides an implementation of the LDAP virtual list view (VLV) 062 * request control as defined in draft-ietf-ldapext-ldapv3-vlv. This control 063 * may be used to retrieve arbitrary "pages" of entries from the complete set of 064 * search results. It is similar to the {@link SimplePagedResultsControl}, with 065 * the exception that the simple paged results control requires scrolling 066 * through the results in sequential order, while the VLV control allows 067 * starting and resuming at any arbitrary point in the result set. The starting 068 * point may be specified using either a positional offset, or based on the 069 * first entry with a value that is greater than or equal to a specified value. 070 * <BR><BR> 071 * When the start of the result set is to be specified using an offset, then the 072 * virtual list view request control should include the following elements: 073 * <UL> 074 * <LI>{@code targetOffset} -- The position in the result set of the entry to 075 * target for the next page of results to return. Note that the offset is 076 * one-based (so the first entry has offset 1, the second entry has offset 077 * 2, etc.).</LI> 078 * <LI>{@code beforeCount} -- The number of entries before the entry specified 079 * as the target offset that should be retrieved.</LI> 080 * <LI>{@code afterCount} -- The number of entries after the entry specified 081 * as the target offset that should be retrieved.</LI> 082 * <LI>{@code contentCount} -- The estimated total number of entries that 083 * are in the total result set. This should be zero for the first request 084 * in a VLV search sequence, but should be the value returned by the 085 * server in the corresponding response control for subsequent searches as 086 * part of the VLV sequence.</LI> 087 * <LI>{@code contextID} -- This is an optional cookie that may be used to 088 * help the server resume processing on a VLV search. It should be absent 089 * from the initial request, but for subsequent requests should be the 090 * value returned in the previous VLV response control.</LI> 091 * </UL> 092 * When the start of the result set is to be specified using a search string, 093 * then the virtual list view request control should include the following 094 * elements: 095 * <UL> 096 * <LI>{@code assertionValue} -- The value that specifies the start of the 097 * page of results to retrieve. The target entry will be the first entry 098 * in which the value for the primary sort attribute is greater than or 099 * equal to this assertion value.</LI> 100 * <LI>{@code beforeCount} -- The number of entries before the entry specified 101 * by the assertion value that should be retrieved.</LI> 102 * <LI>{@code afterCount} -- The number of entries after the entry specified 103 * by the assertion value that should be retrieved.</LI> 104 * <LI>{@code contentCount} -- The estimated total number of entries that 105 * are in the total result set. This should be zero for the first request 106 * in a VLV search sequence, but should be the value returned by the 107 * server in the corresponding response control for subsequent searches as 108 * part of the VLV sequence.</LI> 109 * <LI>{@code contextID} -- This is an optional cookie that may be used to 110 * help the server resume processing on a VLV search. It should be absent 111 * from the initial request, but for subsequent requests should be the 112 * value returned in the previous VLV response control.</LI> 113 * </UL> 114 * Note that the virtual list view request control may only be included in a 115 * search request if that search request also includes the 116 * {@link ServerSideSortRequestControl}. This is necessary to ensure that a 117 * consistent order is used for the resulting entries. 118 * <BR><BR> 119 * If the search is successful, then the search result done response may include 120 * a {@link VirtualListViewResponseControl} to provide information about the 121 * state of the virtual list view processing. 122 * <BR><BR> 123 * <H2>Example</H2> 124 * The following example demonstrates the use of the virtual list view request 125 * control to iterate through all users, retrieving up to 10 entries at a time: 126 * <PRE> 127 * // Perform a search to retrieve all users in the server, but only retrieving 128 * // ten at a time. Ensure that the users are sorted in ascending order by 129 * // last name, then first name. 130 * int numSearches = 0; 131 * int totalEntriesReturned = 0; 132 * SearchRequest searchRequest = new SearchRequest("dc=example,dc=com", 133 * SearchScope.SUB, Filter.createEqualityFilter("objectClass", "person")); 134 * int vlvOffset = 1; 135 * int vlvContentCount = 0; 136 * ASN1OctetString vlvContextID = null; 137 * while (true) 138 * { 139 * // Note that the VLV control always requires the server-side sort 140 * // control. 141 * searchRequest.setControls( 142 * new ServerSideSortRequestControl(new SortKey("sn"), 143 * new SortKey("givenName")), 144 * new VirtualListViewRequestControl(vlvOffset, 0, 9, vlvContentCount, 145 * vlvContextID)); 146 * SearchResult searchResult = connection.search(searchRequest); 147 * numSearches++; 148 * totalEntriesReturned += searchResult.getEntryCount(); 149 * for (SearchResultEntry e : searchResult.getSearchEntries()) 150 * { 151 * // Do something with each entry... 152 * } 153 * 154 * LDAPTestUtils.assertHasControl(searchResult, 155 * VirtualListViewResponseControl.VIRTUAL_LIST_VIEW_RESPONSE_OID); 156 * VirtualListViewResponseControl vlvResponseControl = 157 * VirtualListViewResponseControl.get(searchResult); 158 * vlvContentCount = vlvResponseControl.getContentCount(); 159 * vlvOffset += 10; 160 * vlvContextID = vlvResponseControl.getContextID(); 161 * if (vlvOffset > vlvContentCount) 162 * { 163 * break; 164 * } 165 * } 166 * </PRE> 167 */ 168@NotMutable() 169@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 170public final class VirtualListViewRequestControl 171 extends Control 172{ 173 /** 174 * The OID (2.16.840.1.113730.3.4.9) for the virtual list view request 175 * control. 176 */ 177 @NotNull public static final String VIRTUAL_LIST_VIEW_REQUEST_OID = 178 "2.16.840.1.113730.3.4.9"; 179 180 181 182 /** 183 * The BER type that will be used for the target element when the target is 184 * specified by offset. 185 */ 186 private static final byte TARGET_TYPE_OFFSET = (byte) 0xA0; 187 188 189 190 /** 191 * The BER type that will be used for the target element when the target is 192 * specified by an assertion value. 193 */ 194 private static final byte TARGET_TYPE_GREATER_OR_EQUAL = (byte) 0x81; 195 196 197 198 /** 199 * The serial version UID for this serializable class. 200 */ 201 private static final long serialVersionUID = 4348423177859960815L; 202 203 204 205 // The assertion value that will be used to identify the start of the 206 // requested page of results for a greater-or-equal target type. 207 @Nullable private final ASN1OctetString assertionValue; 208 209 // The context ID that may be used to help the server continue in the same 210 // result set for subsequent searches. 211 @Nullable private final ASN1OctetString contextID; 212 213 // The maximum number of entries to return after the target entry. 214 private final int afterCount; 215 216 // The maximum number of entries to return before the target entry. 217 private final int beforeCount; 218 219 // The estimated number of entries in the complete result set. 220 private final int contentCount; 221 222 // The position of the entry at the start of the requested page of results for 223 // an offset-based target type. 224 private final int targetOffset; 225 226 227 228 /** 229 * Creates a new virtual list view request control that will identify the 230 * beginning of the result set by a target offset. It will be marked 231 * critical. 232 * 233 * @param targetOffset The position of the entry that should be used as the 234 * start of the result set. 235 * @param beforeCount The maximum number of entries that should be returned 236 * before the entry with the specified target offset. 237 * @param afterCount The maximum number of entries that should be returned 238 * after the entry with the specified target offset. 239 * @param contentCount The estimated number of entries in the result set. 240 * For the first request in a series of searches with 241 * the VLV control, it should be zero. For subsequent 242 * searches in the VLV sequence, it should be the 243 * content count included in the response control from 244 * the previous search. 245 * @param contextID The context ID that may be used to help the server 246 * continue in the same result set for subsequent 247 * searches. For the first request in a series of 248 * searches with the VLV control, it should be 249 * {@code null}. For subsequent searches in the VLV 250 * sequence, it should be the (possibly {@code null}) 251 * context ID included in the response control from the 252 * previous search. 253 */ 254 public VirtualListViewRequestControl(final int targetOffset, 255 final int beforeCount, final int afterCount, 256 final int contentCount, 257 @Nullable final ASN1OctetString contextID) 258 { 259 this(targetOffset, beforeCount, afterCount, contentCount, contextID, true); 260 } 261 262 263 264 /** 265 * Creates a new virtual list view request control that will identify the 266 * beginning of the result set by an assertion value. It will be marked 267 * critical. 268 * 269 * @param assertionValue The assertion value that will be used to identify 270 * the start of the result set. The target entry will 271 * be the first entry with a value for the primary 272 * sort attribute that is greater than or equal to 273 * this assertion value. It must not be {@code null}. 274 * @param beforeCount The maximum number of entries that should be 275 * returned before the first entry with a value 276 * greater than or equal to the provided assertion 277 * value. 278 * @param afterCount The maximum number of entries that should be 279 * returned after the first entry with a value 280 * greater than or equal to the provided assertion 281 * value. 282 * @param contextID The context ID that may be used to help the server 283 * continue in the same result set for subsequent 284 * searches. For the first request in a series of 285 * searches with the VLV control, it should be 286 * {@code null}. For subsequent searches in the VLV 287 * sequence, it should be the (possibly {@code null}) 288 * context ID included in the response control from 289 * the previous search. 290 */ 291 public VirtualListViewRequestControl(@NotNull final String assertionValue, 292 final int beforeCount, final int afterCount, 293 @Nullable final ASN1OctetString contextID) 294 { 295 this(new ASN1OctetString(assertionValue), beforeCount, afterCount, 296 contextID, true); 297 } 298 299 300 301 /** 302 * Creates a new virtual list view request control that will identify the 303 * beginning of the result set by an assertion value. It will be marked 304 * critical. 305 * 306 * @param assertionValue The assertion value that will be used to identify 307 * the start of the result set. The target entry will 308 * be the first entry with a value for the primary 309 * sort attribute that is greater than or equal to 310 * this assertion value. It must not be {@code null}. 311 * @param beforeCount The maximum number of entries that should be 312 * returned before the first entry with a value 313 * greater than or equal to the provided assertion 314 * value. 315 * @param afterCount The maximum number of entries that should be 316 * returned after the first entry with a value 317 * greater than or equal to the provided assertion 318 * value. 319 * @param contextID The context ID that may be used to help the server 320 * continue in the same result set for subsequent 321 * searches. For the first request in a series of 322 * searches with the VLV control, it should be 323 * {@code null}. For subsequent searches in the VLV 324 * sequence, it should be the (possibly {@code null}) 325 * context ID included in the response control from 326 * the previous search. 327 */ 328 public VirtualListViewRequestControl(@NotNull final byte[] assertionValue, 329 final int beforeCount, final int afterCount, 330 @Nullable final ASN1OctetString contextID) 331 { 332 this(new ASN1OctetString(assertionValue), beforeCount, afterCount, 333 contextID, true); 334 } 335 336 337 338 /** 339 * Creates a new virtual list view request control that will identify the 340 * beginning of the result set by an assertion value. It will be marked 341 * critical. 342 * 343 * @param assertionValue The assertion value that will be used to identify 344 * the start of the result set. The target entry will 345 * be the first entry with a value for the primary 346 * sort attribute that is greater than or equal to 347 * this assertion value. It must not be {@code null}. 348 * @param beforeCount The maximum number of entries that should be 349 * returned before the first entry with a value 350 * greater than or equal to the provided assertion 351 * value. 352 * @param afterCount The maximum number of entries that should be 353 * returned after the first entry with a value 354 * greater than or equal to the provided assertion 355 * value. 356 * @param contextID The context ID that may be used to help the server 357 * continue in the same result set for subsequent 358 * searches. For the first request in a series of 359 * searches with the VLV control, it should be 360 * {@code null}. For subsequent searches in the VLV 361 * sequence, it should be the (possibly {@code null}) 362 * context ID included in the response control from 363 * the previous search. 364 */ 365 public VirtualListViewRequestControl( 366 @NotNull final ASN1OctetString assertionValue, 367 final int beforeCount, final int afterCount, 368 @Nullable final ASN1OctetString contextID) 369 { 370 this(assertionValue, beforeCount, afterCount, contextID, true); 371 } 372 373 374 375 /** 376 * Creates a new virtual list view request control that will identify the 377 * beginning of the result set by a target offset. 378 * 379 * @param targetOffset The position of the entry that should be used as the 380 * start of the result set. 381 * @param beforeCount The maximum number of entries that should be returned 382 * before the entry with the specified target offset. 383 * @param afterCount The maximum number of entries that should be returned 384 * after the entry with the specified target offset. 385 * @param contentCount The estimated number of entries in the result set. 386 * For the first request in a series of searches with 387 * the VLV control, it should be zero. For subsequent 388 * searches in the VLV sequence, it should be the 389 * content count included in the response control from 390 * the previous search. 391 * @param contextID The context ID that may be used to help the server 392 * continue in the same result set for subsequent 393 * searches. For the first request in a series of 394 * searches with the VLV control, it should be 395 * {@code null}. For subsequent searches in the VLV 396 * sequence, it should be the (possibly {@code null}) 397 * context ID included in the response control from the 398 * previous search. 399 * @param isCritical Indicates whether this control should be marked 400 * critical. 401 */ 402 public VirtualListViewRequestControl(final int targetOffset, 403 final int beforeCount, final int afterCount, 404 final int contentCount, 405 @Nullable final ASN1OctetString contextID, 406 final boolean isCritical) 407 { 408 super(VIRTUAL_LIST_VIEW_REQUEST_OID, isCritical, 409 encodeValue(targetOffset, beforeCount, afterCount, contentCount, 410 contextID)); 411 412 this.targetOffset = targetOffset; 413 this.beforeCount = beforeCount; 414 this.afterCount = afterCount; 415 this.contentCount = contentCount; 416 this.contextID = contextID; 417 418 assertionValue = null; 419 } 420 421 422 423 /** 424 * Creates a new virtual list view request control that will identify the 425 * beginning of the result set by an assertion value. It will be marked 426 * critical. 427 * 428 * @param assertionValue The assertion value that will be used to identify 429 * the start of the result set. The target entry will 430 * be the first entry with a value for the primary 431 * sort attribute that is greater than or equal to 432 * this assertion value. It must not be {@code null}. 433 * @param beforeCount The maximum number of entries that should be 434 * returned before the first entry with a value 435 * greater than or equal to the provided assertion 436 * value. 437 * @param afterCount The maximum number of entries that should be 438 * returned after the first entry with a value 439 * greater than or equal to the provided assertion 440 * value. 441 * @param contextID The context ID that may be used to help the server 442 * continue in the same result set for subsequent 443 * searches. For the first request in a series of 444 * searches with the VLV control, it should be 445 * {@code null}. For subsequent searches in the VLV 446 * sequence, it should be the (possibly {@code null}) 447 * context ID included in the response control from 448 * the previous search. 449 * @param isCritical Indicates whether this control should be marked 450 * critical. 451 */ 452 public VirtualListViewRequestControl(@NotNull final String assertionValue, 453 final int beforeCount, final int afterCount, 454 @Nullable final ASN1OctetString contextID, 455 final boolean isCritical) 456 { 457 this(new ASN1OctetString(assertionValue), beforeCount, afterCount, 458 contextID, isCritical); 459 } 460 461 462 463 /** 464 * Creates a new virtual list view request control that will identify the 465 * beginning of the result set by an assertion value. It will be marked 466 * critical. 467 * 468 * @param assertionValue The assertion value that will be used to identify 469 * the start of the result set. The target entry will 470 * be the first entry with a value for the primary 471 * sort attribute that is greater than or equal to 472 * this assertion value. It must not be {@code null}. 473 * @param beforeCount The maximum number of entries that should be 474 * returned before the first entry with a value 475 * greater than or equal to the provided assertion 476 * value. 477 * @param afterCount The maximum number of entries that should be 478 * returned after the first entry with a value 479 * greater than or equal to the provided assertion 480 * value. 481 * @param contextID The context ID that may be used to help the server 482 * continue in the same result set for subsequent 483 * searches. For the first request in a series of 484 * searches with the VLV control, it should be 485 * {@code null}. For subsequent searches in the VLV 486 * sequence, it should be the (possibly {@code null}) 487 * context ID included in the response control from 488 * the previous search. 489 * @param isCritical Indicates whether this control should be marked 490 * critical. 491 */ 492 public VirtualListViewRequestControl(@NotNull final byte[] assertionValue, 493 final int beforeCount, final int afterCount, 494 @Nullable final ASN1OctetString contextID, 495 final boolean isCritical) 496 { 497 this(new ASN1OctetString(assertionValue), beforeCount, afterCount, 498 contextID, isCritical); 499 } 500 501 502 503 /** 504 * Creates a new virtual list view request control that will identify the 505 * beginning of the result set by an assertion value. It will be marked 506 * critical. 507 * 508 * @param assertionValue The assertion value that will be used to identify 509 * the start of the result set. The target entry will 510 * be the first entry with a value for the primary 511 * sort attribute that is greater than or equal to 512 * this assertion value. It must not be {@code null}. 513 * @param beforeCount The maximum number of entries that should be 514 * returned before the first entry with a value 515 * greater than or equal to the provided assertion 516 * value. 517 * @param afterCount The maximum number of entries that should be 518 * returned after the first entry with a value 519 * greater than or equal to the provided assertion 520 * value. 521 * @param contextID The context ID that may be used to help the server 522 * continue in the same result set for subsequent 523 * searches. For the first request in a series of 524 * searches with the VLV control, it should be 525 * {@code null}. For subsequent searches in the VLV 526 * sequence, it should be the (possibly {@code null}) 527 * context ID included in the response control from 528 * the previous search. 529 * @param isCritical Indicates whether this control should be marked 530 * critical. 531 */ 532 public VirtualListViewRequestControl( 533 @NotNull final ASN1OctetString assertionValue, 534 final int beforeCount, final int afterCount, 535 @Nullable final ASN1OctetString contextID, 536 final boolean isCritical) 537 { 538 super(VIRTUAL_LIST_VIEW_REQUEST_OID, isCritical, 539 encodeValue(assertionValue, beforeCount, afterCount, contextID)); 540 541 this.assertionValue = assertionValue; 542 this.beforeCount = beforeCount; 543 this.afterCount = afterCount; 544 this.contextID = contextID; 545 546 targetOffset = -1; 547 contentCount = -1; 548 } 549 550 551 552 /** 553 * Creates a new virtual list view request control which is decoded from the 554 * provided generic control. 555 * 556 * @param control The generic control to be decoded as a virtual list view 557 * request control. 558 * 559 * @throws LDAPException If the provided control cannot be decoded as a 560 * virtual list view request control. 561 */ 562 public VirtualListViewRequestControl(@NotNull final Control control) 563 throws LDAPException 564 { 565 super(control); 566 567 final ASN1OctetString value = control.getValue(); 568 if (value == null) 569 { 570 throw new LDAPException(ResultCode.DECODING_ERROR, 571 ERR_VLV_REQUEST_NO_VALUE.get()); 572 } 573 574 try 575 { 576 final ASN1Element valueElement = ASN1Element.decode(value.getValue()); 577 final ASN1Element[] elements = 578 ASN1Sequence.decodeAsSequence(valueElement).elements(); 579 580 beforeCount = ASN1Integer.decodeAsInteger(elements[0]).intValue(); 581 afterCount = ASN1Integer.decodeAsInteger(elements[1]).intValue(); 582 583 switch (elements[2].getType()) 584 { 585 case TARGET_TYPE_OFFSET: 586 assertionValue = null; 587 final ASN1Element[] offsetElements = 588 ASN1Sequence.decodeAsSequence(elements[2]).elements(); 589 targetOffset = 590 ASN1Integer.decodeAsInteger(offsetElements[0]).intValue(); 591 contentCount = 592 ASN1Integer.decodeAsInteger(offsetElements[1]).intValue(); 593 break; 594 595 case TARGET_TYPE_GREATER_OR_EQUAL: 596 assertionValue = ASN1OctetString.decodeAsOctetString(elements[2]); 597 targetOffset = -1; 598 contentCount = -1; 599 break; 600 601 default: 602 throw new LDAPException(ResultCode.DECODING_ERROR, 603 ERR_VLV_REQUEST_INVALID_ELEMENT_TYPE.get( 604 StaticUtils.toHex(elements[2].getType()))); 605 } 606 607 if (elements.length == 4) 608 { 609 contextID = ASN1OctetString.decodeAsOctetString(elements[3]); 610 } 611 else 612 { 613 contextID = null; 614 } 615 } 616 catch (final LDAPException le) 617 { 618 Debug.debugException(le); 619 throw le; 620 } 621 catch (final Exception e) 622 { 623 Debug.debugException(e); 624 throw new LDAPException(ResultCode.DECODING_ERROR, 625 ERR_VLV_REQUEST_CANNOT_DECODE.get(e), e); 626 } 627 } 628 629 630 631 /** 632 * Encodes the provided information into an octet string that can be used as 633 * the value for this control. 634 * 635 * @param targetOffset The position of the entry that should be used as the 636 * start of the result set. 637 * @param beforeCount The maximum number of entries that should be returned 638 * before the entry with the specified target offset. 639 * @param afterCount The maximum number of entries that should be returned 640 * after the entry with the specified target offset. 641 * @param contentCount The estimated number of entries in the result set. 642 * For the first request in a series of searches with 643 * the VLV control, it should be zero. For subsequent 644 * searches in the VLV sequence, it should be the 645 * content count included in the response control from 646 * the previous search. 647 * @param contextID The context ID that may be used to help the server 648 * continue in the same result set for subsequent 649 * searches. For the first request in a series of 650 * searches with the VLV control, it should be 651 * {@code null}. For subsequent searches in the VLV 652 * sequence, it should be the (possibly {@code null}) 653 * context ID included in the response control from the 654 * previous search. 655 * 656 * @return An ASN.1 octet string that can be used as the value for this 657 * control. 658 */ 659 @NotNull() 660 private static ASN1OctetString encodeValue(final int targetOffset, 661 final int beforeCount, final int afterCount, 662 final int contentCount, 663 @Nullable final ASN1OctetString contextID) 664 { 665 final ASN1Element[] targetElements = 666 { 667 new ASN1Integer(targetOffset), 668 new ASN1Integer(contentCount) 669 }; 670 671 final ASN1Element[] vlvElements; 672 if (contextID == null) 673 { 674 vlvElements = new ASN1Element[] 675 { 676 new ASN1Integer(beforeCount), 677 new ASN1Integer(afterCount), 678 new ASN1Sequence(TARGET_TYPE_OFFSET, targetElements) 679 }; 680 } 681 else 682 { 683 vlvElements = new ASN1Element[] 684 { 685 new ASN1Integer(beforeCount), 686 new ASN1Integer(afterCount), 687 new ASN1Sequence(TARGET_TYPE_OFFSET, targetElements), 688 contextID 689 }; 690 } 691 692 return new ASN1OctetString(new ASN1Sequence(vlvElements).encode()); 693 } 694 695 696 697 /** 698 * Encodes the provided information into an octet string that can be used as 699 * the value for this control. 700 * 701 * @param assertionValue The assertion value that will be used to identify 702 * the start of the result set. The target entry will 703 * be the first entry with a value for the primary 704 * sort attribute that is greater than or equal to 705 * this assertion value. 706 * @param beforeCount The maximum number of entries that should be 707 * returned before the first entry with a value 708 * greater than or equal to the provided assertion 709 * value. 710 * @param afterCount The maximum number of entries that should be 711 * returned after the first entry with a value 712 * greater than or equal to the provided assertion 713 * value. 714 * @param contextID The context ID that may be used to help the server 715 * continue in the same result set for subsequent 716 * searches. For the first request in a series of 717 * searches with the VLV control, it should be 718 * {@code null}. For subsequent searches in the VLV 719 * sequence, it should be the (possibly {@code null}) 720 * context ID included in the response control from 721 * the previous search. 722 * 723 * @return An ASN.1 octet string that can be used as the value for this 724 * control. 725 */ 726 @NotNull() 727 private static ASN1OctetString encodeValue( 728 @NotNull final ASN1OctetString assertionValue, 729 final int beforeCount, 730 final int afterCount, 731 @Nullable final ASN1OctetString contextID) 732 { 733 Validator.ensureNotNull(assertionValue); 734 735 final ASN1Element[] vlvElements; 736 if (contextID == null) 737 { 738 vlvElements = new ASN1Element[] 739 { 740 new ASN1Integer(beforeCount), 741 new ASN1Integer(afterCount), 742 new ASN1OctetString(TARGET_TYPE_GREATER_OR_EQUAL, 743 assertionValue.getValue()) 744 }; 745 } 746 else 747 { 748 vlvElements = new ASN1Element[] 749 { 750 new ASN1Integer(beforeCount), 751 new ASN1Integer(afterCount), 752 new ASN1OctetString(TARGET_TYPE_GREATER_OR_EQUAL, 753 assertionValue.getValue()), 754 contextID 755 }; 756 } 757 758 return new ASN1OctetString(new ASN1Sequence(vlvElements).encode()); 759 } 760 761 762 763 /** 764 * Retrieves the target offset position for this virtual list view request 765 * control, if applicable. 766 * 767 * @return The target offset position for this virtual list view request 768 * control, or -1 if the target is specified by an assertion value. 769 */ 770 public int getTargetOffset() 771 { 772 return targetOffset; 773 } 774 775 776 777 /** 778 * Retrieves the string representation of the assertion value for this virtual 779 * list view request control, if applicable. 780 * 781 * @return The string representation of the assertion value for this virtual 782 * list view request control, or {@code null} if the target is 783 * specified by offset. 784 */ 785 @Nullable() 786 public String getAssertionValueString() 787 { 788 if (assertionValue == null) 789 { 790 return null; 791 } 792 else 793 { 794 return assertionValue.stringValue(); 795 } 796 } 797 798 799 800 /** 801 * Retrieves the byte array representation of the assertion value for this 802 * virtual list view request control, if applicable. 803 * 804 * @return The byte array representation of the assertion value for this 805 * virtual list view request control, or {@code null} if the target 806 * is specified by offset. 807 */ 808 @Nullable() 809 public byte[] getAssertionValueBytes() 810 { 811 if (assertionValue == null) 812 { 813 return null; 814 } 815 else 816 { 817 return assertionValue.getValue(); 818 } 819 } 820 821 822 823 /** 824 * Retrieves the assertion value for this virtual list view request control, 825 * if applicable. 826 * 827 * @return The assertion value for this virtual list view request control, or 828 * {@code null} if the target is specified by offset. 829 */ 830 @Nullable() 831 public ASN1OctetString getAssertionValue() 832 { 833 return assertionValue; 834 } 835 836 837 838 /** 839 * Retrieves the number of entries that should be retrieved before the target 840 * entry. 841 * 842 * @return The number of entries that should be retrieved before the target 843 * entry. 844 */ 845 public int getBeforeCount() 846 { 847 return beforeCount; 848 } 849 850 851 852 /** 853 * Retrieves the number of entries that should be retrieved after the target 854 * entry. 855 * 856 * @return The number of entries that should be retrieved after the target 857 * entry. 858 */ 859 public int getAfterCount() 860 { 861 return afterCount; 862 } 863 864 865 866 /** 867 * Retrieves the estimated number of entries in the result set, if applicable. 868 * 869 * @return The estimated number of entries in the result set, zero if it 870 * is not known (for the first search in a sequence where the 871 * target is specified by offset), or -1 if the target is specified 872 * by an assertion value. 873 */ 874 public int getContentCount() 875 { 876 return contentCount; 877 } 878 879 880 881 /** 882 * Retrieves the context ID for this virtual list view request control, if 883 * available. 884 * 885 * @return The context ID for this virtual list view request control, or 886 * {@code null} if there is none. 887 */ 888 @Nullable() 889 public ASN1OctetString getContextID() 890 { 891 return contextID; 892 } 893 894 895 896 /** 897 * {@inheritDoc} 898 */ 899 @Override() 900 @NotNull() 901 public String getControlName() 902 { 903 return INFO_CONTROL_NAME_VLV_REQUEST.get(); 904 } 905 906 907 908 /** 909 * {@inheritDoc} 910 */ 911 @Override() 912 public void toString(@NotNull final StringBuilder buffer) 913 { 914 buffer.append("VirtualListViewRequestControl(beforeCount="); 915 buffer.append(beforeCount); 916 buffer.append(", afterCount="); 917 buffer.append(afterCount); 918 919 if (assertionValue == null) 920 { 921 buffer.append(", targetOffset="); 922 buffer.append(targetOffset); 923 buffer.append(", contentCount="); 924 buffer.append(contentCount); 925 } 926 else 927 { 928 buffer.append(", assertionValue='"); 929 buffer.append(assertionValue.stringValue()); 930 buffer.append('\''); 931 } 932 933 buffer.append(", isCritical="); 934 buffer.append(isCritical()); 935 buffer.append(')'); 936 } 937}