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