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 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.controls;
028import org.forgerock.i18n.LocalizableMessage;
029
030
031import java.io.IOException;
032
033import org.forgerock.opendj.io.*;
034import org.opends.server.types.*;
035import org.forgerock.opendj.ldap.ResultCode;
036import org.forgerock.opendj.ldap.ByteString;
037import static org.opends.messages.ProtocolMessages.*;
038import static org.opends.server.util.ServerConstants.*;
039import static org.opends.server.util.StaticUtils.*;
040
041
042
043/**
044 * This class implements the virtual list view response controls as defined in
045 * draft-ietf-ldapext-ldapv3-vlv.  The ASN.1 description for the control value
046 * is:
047 * <BR><BR>
048 * <PRE>
049 * VirtualListViewResponse ::= SEQUENCE {
050 *       targetPosition    INTEGER (0 .. maxInt),
051 *       contentCount     INTEGER (0 .. maxInt),
052 *       virtualListViewResult ENUMERATED {
053 *            success (0),
054 *            operationsError (1),
055 *            protocolError (3),
056 *            unwillingToPerform (53),
057 *            insufficientAccessRights (50),
058 *            timeLimitExceeded (3),
059 *            adminLimitExceeded (11),
060 *            inappropriateMatching (18),
061 *            sortControlMissing (60),
062 *            offsetRangeError (61),
063 *            other(80),
064 *            ... },
065 *       contextID     OCTET STRING OPTIONAL }
066 * </PRE>
067 */
068public class VLVResponseControl
069       extends Control
070{
071  /**
072   * ControlDecoder implementation to decode this control from a ByteString.
073   */
074  private static final class Decoder
075      implements ControlDecoder<VLVResponseControl>
076  {
077    /** {@inheritDoc} */
078    public VLVResponseControl decode(boolean isCritical, ByteString value)
079        throws DirectoryException
080    {
081      if (value == null)
082      {
083        LocalizableMessage message = INFO_VLVRES_CONTROL_NO_VALUE.get();
084        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
085      }
086
087      ASN1Reader reader = ASN1.getReader(value);
088      try
089      {
090        reader.readStartSequence();
091
092        int targetPosition = (int)reader.readInteger();
093        int contentCount   = (int)reader.readInteger();
094        int vlvResultCode  = (int)reader.readInteger();
095
096        ByteString contextID = null;
097        if (reader.hasNextElement())
098        {
099          contextID = reader.readOctetString();
100        }
101
102        return new VLVResponseControl(isCritical, targetPosition,
103            contentCount, vlvResultCode, contextID);
104      }
105      catch (Exception e)
106      {
107        LocalizableMessage message =
108            INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
109        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
110      }
111    }
112
113    /** {@inheritDoc} */
114    public String getOID()
115    {
116      return OID_VLV_RESPONSE_CONTROL;
117    }
118  }
119
120  /**
121   * The Control Decoder that can be used to decode this control.
122   */
123  public static final ControlDecoder<VLVResponseControl> DECODER =
124    new Decoder();
125
126  /** The context ID for this VLV response control. */
127  private ByteString contextID;
128
129  /** The content count estimating the total number of entries in the result set. */
130  private int contentCount;
131
132  /** The offset of the target entry in the result set. */
133  private int targetPosition;
134
135  /** The result code for the VLV operation. */
136  private int vlvResultCode;
137
138
139
140  /**
141   * Creates a new VLV response control with the provided information.
142   *
143   * @param  targetPosition  The position of the target entry in the result set.
144   * @param  contentCount    The content count estimating the total number of
145   *                         entries in the result set.
146   * @param  vlvResultCode   The result code for the VLV operation.
147   */
148  public VLVResponseControl(int targetPosition, int contentCount,
149                            int vlvResultCode)
150  {
151    this(false, targetPosition, contentCount, vlvResultCode, null);
152  }
153
154
155
156  /**
157   * Creates a new VLV response control with the provided information.
158   *
159   * @param  isCritical      Indicates whether the control should be considered
160   *                         critical.
161   * @param  targetPosition  The position of the target entry in the result set.
162   * @param  contentCount    The content count estimating the total number of
163   *                         entries in the result set.
164   * @param  vlvResultCode   The result code for the VLV operation.
165   * @param  contextID       The context ID for this VLV response control.
166   */
167  public VLVResponseControl(boolean isCritical, int targetPosition,
168                             int contentCount, int vlvResultCode,
169                             ByteString contextID)
170  {
171    super(OID_VLV_RESPONSE_CONTROL, isCritical);
172
173    this.targetPosition = targetPosition;
174    this.contentCount   = contentCount;
175    this.vlvResultCode  = vlvResultCode;
176    this.contextID      = contextID;
177  }
178
179
180
181  /**
182   * Retrieves the position of the target entry in the result set.
183   *
184   * @return  The position of the target entry in the result set.
185   */
186  public int getTargetPosition()
187  {
188    return targetPosition;
189  }
190
191
192
193  /**
194   * Retrieves the estimated total number of entries in the result set.
195   *
196   * @return  The estimated total number of entries in the result set.
197   */
198  public int getContentCount()
199  {
200    return contentCount;
201  }
202
203
204
205  /**
206   * Retrieves the result code for the VLV operation.
207   *
208   * @return  The result code for the VLV operation.
209   */
210  public int getVLVResultCode()
211  {
212    return vlvResultCode;
213  }
214
215
216
217  /**
218   * Retrieves a context ID value that should be included in the next request
219   * to retrieve a page of the same result set.
220   *
221   * @return  A context ID value that should be included in the next request to
222   *          retrieve a page of the same result set, or {@code null} if there
223   *          is no context ID.
224   */
225  public ByteString getContextID()
226  {
227    return contextID;
228  }
229
230
231
232  /**
233   * Writes this control's value to an ASN.1 writer. The value (if any) must be
234   * written as an ASN1OctetString.
235   *
236   * @param writer The ASN.1 writer to use.
237   * @throws IOException If a problem occurs while writing to the stream.
238   */
239  @Override
240  protected void writeValue(ASN1Writer writer) throws IOException {
241    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
242
243    writer.writeStartSequence();
244    writer.writeInteger(targetPosition);
245    writer.writeInteger(contentCount);
246    writer.writeEnumerated(vlvResultCode);
247    if (contextID != null)
248    {
249      writer.writeOctetString(contextID);
250    }
251    writer.writeEndSequence();
252
253    writer.writeEndSequence();
254  }
255
256
257
258  /**
259   * Appends a string representation of this VLV request control to the provided
260   * buffer.
261   *
262   * @param  buffer  The buffer to which the information should be appended.
263   */
264  @Override
265  public void toString(StringBuilder buffer)
266  {
267    buffer.append("VLVResponseControl(targetPosition=");
268    buffer.append(targetPosition);
269    buffer.append(", contentCount=");
270    buffer.append(contentCount);
271    buffer.append(", vlvResultCode=");
272    buffer.append(vlvResultCode);
273
274    if (contextID != null)
275    {
276      buffer.append(", contextID=");
277      buffer.append(contextID);
278    }
279
280    buffer.append(")");
281  }
282}
283