001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.controls;
028
029import org.forgerock.i18n.LocalizableMessage;
030
031import org.forgerock.i18n.slf4j.LocalizedLogger;
032import static org.opends.messages.ProtocolMessages.*;
033import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL;
034
035import org.forgerock.opendj.io.*;
036import org.opends.server.types.*;
037import org.forgerock.opendj.ldap.ResultCode;
038import org.forgerock.opendj.ldap.ByteString;
039import java.io.IOException;
040
041/**
042 * This class represents a paged results control value as defined in
043 * RFC 2696.
044 *
045 * The searchControlValue is an OCTET STRING wrapping the BER-encoded
046 * version of the following SEQUENCE:
047 *
048 * <pre>
049 * realSearchControlValue ::= SEQUENCE {
050 *         size            INTEGER (0..maxInt),
051 *                                 -- requested page size from client
052 *                                 -- result set size estimate from server
053 *         cookie          OCTET STRING
054 * }
055 * </pre>
056 */
057public class PagedResultsControl extends Control
058{
059  /**
060   * ControlDecoder implementation to decode this control from a ByteString.
061   */
062  private static final class Decoder
063      implements ControlDecoder<PagedResultsControl>
064  {
065    /** {@inheritDoc} */
066    public PagedResultsControl decode(boolean isCritical, ByteString value)
067        throws DirectoryException
068    {
069      if (value == null)
070      {
071        LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL.get();
072        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
073      }
074
075      ASN1Reader reader = ASN1.getReader(value);
076      try
077      {
078        reader.readStartSequence();
079      }
080      catch (Exception e)
081      {
082        logger.traceException(e);
083
084        LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(e);
085        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
086      }
087
088      int size;
089      try
090      {
091        size = (int)reader.readInteger();
092      }
093      catch (Exception e)
094      {
095        logger.traceException(e);
096
097        LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SIZE.get(e);
098        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
099      }
100
101      ByteString cookie;
102      try
103      {
104        cookie = reader.readOctetString();
105      }
106      catch (Exception e)
107      {
108        logger.traceException(e);
109
110        LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE.get(e);
111        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
112      }
113
114      try
115      {
116        reader.readEndSequence();
117      }
118      catch (Exception e)
119      {
120        logger.traceException(e);
121
122        LocalizableMessage message = ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(e);
123        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
124      }
125
126      return new PagedResultsControl(isCritical, size, cookie);
127    }
128
129    public String getOID()
130    {
131      return OID_PAGED_RESULTS_CONTROL;
132    }
133
134  }
135
136  /**
137   * The Control Decoder that can be used to decode this control.
138   */
139  public static final  ControlDecoder<PagedResultsControl> DECODER =
140    new Decoder();
141  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
142
143
144
145  /**
146   * The control value size element, which is either the requested page size
147   * from the client, or the result set size estimate from the server.
148   */
149  private int size;
150
151
152  /**
153   * The control value cookie element.
154   */
155  private ByteString cookie;
156
157
158  /**
159   * Creates a new paged results control with the specified information.
160   *
161   * @param  isCritical  Indicates whether this control should be considered
162   *                     critical in processing the request.
163   * @param  size        The size element.
164   * @param  cookie      The cookie element.
165   */
166  public PagedResultsControl(boolean isCritical, int size,
167                             ByteString cookie)
168  {
169    super(OID_PAGED_RESULTS_CONTROL, isCritical);
170
171
172    this.size   = size;
173    if(cookie == null)
174    {
175      this.cookie=ByteString.empty();
176    }
177    else
178    {
179      this.cookie = cookie;
180    }
181  }
182
183
184  /**
185   * Writes this control's value to an ASN.1 writer. The value (if any) must be
186   * written as an ASN1OctetString.
187   *
188   * @param writer The ASN.1 output stream to write to.
189   * @throws IOException If a problem occurs while writing to the stream.
190   */
191  @Override
192  public void writeValue(ASN1Writer writer) throws IOException {
193    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
194
195    writer.writeStartSequence();
196    writer.writeInteger(size);
197    writer.writeOctetString(cookie);
198    writer.writeEndSequence();
199
200    writer.writeEndSequence();
201  }
202
203
204  /**
205   * Get the control value size element, which is either the requested page size
206   * from the client, or the result set size estimate from the server.
207   * @return The control value size element.
208   */
209  public int getSize()
210  {
211    return size;
212  }
213
214
215
216  /**
217   * Get the control value cookie element.
218   * @return The control value cookie element.
219   */
220  public ByteString getCookie()
221  {
222    return cookie;
223  }
224}