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