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