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 &gt; 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}