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