001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 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 &gt; 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}