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-2015 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  /**
062   * ControlDecoder implementation to decode this control from a ByteString.
063   */
064  private static final class Decoder
065      implements ControlDecoder<VLVResponseControl>
066  {
067    /** {@inheritDoc} */
068    public VLVResponseControl decode(boolean isCritical, ByteString value)
069        throws DirectoryException
070    {
071      if (value == null)
072      {
073        LocalizableMessage message = INFO_VLVRES_CONTROL_NO_VALUE.get();
074        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
075      }
076
077      ASN1Reader reader = ASN1.getReader(value);
078      try
079      {
080        reader.readStartSequence();
081
082        int targetPosition = (int)reader.readInteger();
083        int contentCount   = (int)reader.readInteger();
084        int vlvResultCode  = (int)reader.readInteger();
085
086        ByteString contextID = null;
087        if (reader.hasNextElement())
088        {
089          contextID = reader.readOctetString();
090        }
091
092        return new VLVResponseControl(isCritical, targetPosition,
093            contentCount, vlvResultCode, contextID);
094      }
095      catch (Exception e)
096      {
097        LocalizableMessage message =
098            INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
099        throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
100      }
101    }
102
103    /** {@inheritDoc} */
104    public String getOID()
105    {
106      return OID_VLV_RESPONSE_CONTROL;
107    }
108  }
109
110  /**
111   * The Control Decoder that can be used to decode this control.
112   */
113  public static final ControlDecoder<VLVResponseControl> DECODER =
114    new Decoder();
115
116  /** The context ID for this VLV response control. */
117  private ByteString contextID;
118
119  /** The content count estimating the total number of entries in the result set. */
120  private int contentCount;
121
122  /** The offset of the target entry in the result set. */
123  private int targetPosition;
124
125  /** The result code for the VLV operation. */
126  private int vlvResultCode;
127
128
129
130  /**
131   * Creates a new VLV response control with the provided information.
132   *
133   * @param  targetPosition  The position of the target entry in the result set.
134   * @param  contentCount    The content count estimating the total number of
135   *                         entries in the result set.
136   * @param  vlvResultCode   The result code for the VLV operation.
137   */
138  public VLVResponseControl(int targetPosition, int contentCount,
139                            int vlvResultCode)
140  {
141    this(false, targetPosition, contentCount, vlvResultCode, null);
142  }
143
144
145
146  /**
147   * Creates a new VLV response control with the provided information.
148   *
149   * @param  isCritical      Indicates whether the control should be considered
150   *                         critical.
151   * @param  targetPosition  The position of the target entry in the result set.
152   * @param  contentCount    The content count estimating the total number of
153   *                         entries in the result set.
154   * @param  vlvResultCode   The result code for the VLV operation.
155   * @param  contextID       The context ID for this VLV response control.
156   */
157  public VLVResponseControl(boolean isCritical, int targetPosition,
158                             int contentCount, int vlvResultCode,
159                             ByteString contextID)
160  {
161    super(OID_VLV_RESPONSE_CONTROL, isCritical);
162
163    this.targetPosition = targetPosition;
164    this.contentCount   = contentCount;
165    this.vlvResultCode  = vlvResultCode;
166    this.contextID      = contextID;
167  }
168
169
170
171  /**
172   * Retrieves the position of the target entry in the result set.
173   *
174   * @return  The position of the target entry in the result set.
175   */
176  public int getTargetPosition()
177  {
178    return targetPosition;
179  }
180
181
182
183  /**
184   * Retrieves the estimated total number of entries in the result set.
185   *
186   * @return  The estimated total number of entries in the result set.
187   */
188  public int getContentCount()
189  {
190    return contentCount;
191  }
192
193
194
195  /**
196   * Retrieves the result code for the VLV operation.
197   *
198   * @return  The result code for the VLV operation.
199   */
200  public int getVLVResultCode()
201  {
202    return vlvResultCode;
203  }
204
205
206
207  /**
208   * Retrieves a context ID value that should be included in the next request
209   * to retrieve a page of the same result set.
210   *
211   * @return  A context ID value that should be included in the next request to
212   *          retrieve a page of the same result set, or {@code null} if there
213   *          is no context ID.
214   */
215  public ByteString getContextID()
216  {
217    return contextID;
218  }
219
220
221
222  /**
223   * Writes this control's value to an ASN.1 writer. The value (if any) must be
224   * written as an ASN1OctetString.
225   *
226   * @param writer The ASN.1 writer to use.
227   * @throws IOException If a problem occurs while writing to the stream.
228   */
229  @Override
230  protected void writeValue(ASN1Writer writer) throws IOException {
231    writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE);
232
233    writer.writeStartSequence();
234    writer.writeInteger(targetPosition);
235    writer.writeInteger(contentCount);
236    writer.writeEnumerated(vlvResultCode);
237    if (contextID != null)
238    {
239      writer.writeOctetString(contextID);
240    }
241    writer.writeEndSequence();
242
243    writer.writeEndSequence();
244  }
245
246
247
248  /**
249   * Appends a string representation of this VLV request control to the provided
250   * buffer.
251   *
252   * @param  buffer  The buffer to which the information should be appended.
253   */
254  @Override
255  public void toString(StringBuilder buffer)
256  {
257    buffer.append("VLVResponseControl(targetPosition=");
258    buffer.append(targetPosition);
259    buffer.append(", contentCount=");
260    buffer.append(contentCount);
261    buffer.append(", vlvResultCode=");
262    buffer.append(vlvResultCode);
263
264    if (contextID != null)
265    {
266      buffer.append(", contextID=");
267      buffer.append(contextID);
268    }
269
270    buffer.append(")");
271  }
272}
273