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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.controls;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    
034    import org.opends.server.protocols.asn1.ASN1Element;
035    import org.opends.server.protocols.asn1.ASN1Enumerated;
036    import org.opends.server.protocols.asn1.ASN1Integer;
037    import org.opends.server.protocols.asn1.ASN1OctetString;
038    import org.opends.server.protocols.asn1.ASN1Sequence;
039    import org.opends.server.protocols.ldap.LDAPResultCode;
040    import org.opends.server.types.ByteString;
041    import org.opends.server.types.Control;
042    import org.opends.server.types.LDAPException;
043    
044    import static org.opends.messages.ProtocolMessages.*;
045    import static org.opends.server.util.ServerConstants.*;
046    import static org.opends.server.util.StaticUtils.*;
047    
048    
049    
050    /**
051     * This class implements the virtual list view response controls as defined in
052     * draft-ietf-ldapext-ldapv3-vlv.  The ASN.1 description for the control value
053     * is:
054     * <BR><BR>
055     * <PRE>
056     * VirtualListViewResponse ::= SEQUENCE {
057     *       targetPosition    INTEGER (0 .. maxInt),
058     *       contentCount     INTEGER (0 .. maxInt),
059     *       virtualListViewResult ENUMERATED {
060     *            success (0),
061     *            operationsError (1),
062     *            protocolError (3),
063     *            unwillingToPerform (53),
064     *            insufficientAccessRights (50),
065     *            timeLimitExceeded (3),
066     *            adminLimitExceeded (11),
067     *            innapropriateMatching (18),
068     *            sortControlMissing (60),
069     *            offsetRangeError (61),
070     *            other(80),
071     *            ... },
072     *       contextID     OCTET STRING OPTIONAL }
073     * </PRE>
074     */
075    public class VLVResponseControl
076           extends Control
077    {
078      // The context ID for this VLV response control.
079      private ByteString contextID;
080    
081      // The content count estimating the total number of entries in the result set.
082      private int contentCount;
083    
084      // The offset of the target entry in the result set.
085      private int targetPosition;
086    
087      // The result code for the VLV operation.
088      private int vlvResultCode;
089    
090    
091    
092      /**
093       * Creates a new VLV response control with the provided information.
094       *
095       * @param  targetPosition  The position of the target entry in the result set.
096       * @param  contentCount    The content count estimating the total number of
097       *                         entries in the result set.
098       * @param  vlvResultCode   The result code for the VLV operation.
099       */
100      public VLVResponseControl(int targetPosition, int contentCount,
101                                int vlvResultCode)
102      {
103        this(targetPosition, contentCount, vlvResultCode, null);
104      }
105    
106    
107    
108      /**
109       * Creates a new VLV response control with the provided information.
110       *
111       * @param  targetPosition  The position of the target entry in the result set.
112       * @param  contentCount    The content count estimating the total number of
113       *                         entries in the result set.
114       * @param  vlvResultCode   The result code for the VLV operation.
115       * @param  contextID       The context ID for this VLV response control.
116       */
117      public VLVResponseControl(int targetPosition, int contentCount,
118                                int vlvResultCode, ByteString contextID)
119      {
120        super(OID_VLV_RESPONSE_CONTROL, false,
121              encodeControlValue(targetPosition, contentCount, vlvResultCode,
122                                 contextID));
123    
124        this.targetPosition = targetPosition;
125        this.contentCount   = contentCount;
126        this.vlvResultCode  = vlvResultCode;
127        this.contextID      = contextID;
128      }
129    
130    
131    
132      /**
133       * Creates a new VLV response control with the provided information.
134       *
135       * @param  oid             The OID for the control.
136       * @param  isCritical      Indicates whether the control should be considered
137       *                         critical.
138       * @param  controlValue    The pre-encoded value for the control.
139       * @param  targetPosition  The position of the target entry in the result set.
140       * @param  contentCount    The content count estimating the total number of
141       *                         entries in the result set.
142       * @param  vlvResultCode   The result code for the VLV operation.
143       * @param  contextID       The context ID for this VLV response control.
144       */
145      private VLVResponseControl(String oid, boolean isCritical,
146                                 ASN1OctetString controlValue, int targetPosition,
147                                 int contentCount, int vlvResultCode,
148                                 ByteString contextID)
149      {
150        super(oid, isCritical, controlValue);
151    
152        this.targetPosition = targetPosition;
153        this.contentCount   = contentCount;
154        this.vlvResultCode  = vlvResultCode;
155        this.contextID      = contextID;
156      }
157    
158    
159    
160      /**
161       * Retrieves the position of the target entry in the result set.
162       *
163       * @return  The position of the target entry in the result set.
164       */
165      public int getTargetPosition()
166      {
167        return targetPosition;
168      }
169    
170    
171    
172      /**
173       * Retrieves the estimated total number of entries in the result set.
174       *
175       * @return  The estimated total number of entries in the result set.
176       */
177      public int getContentCount()
178      {
179        return contentCount;
180      }
181    
182    
183    
184      /**
185       * Retrieves the result code for the VLV operation.
186       *
187       * @return  The result code for the VLV operation.
188       */
189      public int getVLVResultCode()
190      {
191        return vlvResultCode;
192      }
193    
194    
195    
196      /**
197       * Retrieves a context ID value that should be included in the next request
198       * to retrieve a page of the same result set.
199       *
200       * @return  A context ID value that should be included in the next request to
201       *          retrieve a page of the same result set, or {@code null} if there
202       *          is no context ID.
203       */
204      public ByteString getContextID()
205      {
206        return contextID;
207      }
208    
209    
210    
211      /**
212       * Encodes the provided information in a manner suitable for use as the value
213       * of this control.
214       *
215       * @param  targetPosition  The position of the target entry in the result set.
216       * @param  contentCount    The content count estimating the total number of
217       *                         entries in the result set.
218       * @param  vlvResultCode   The result code for the VLV operation.
219       * @param  contextID       The context ID for this VLV response control.
220       *
221       * @return  The ASN.1 octet string containing the encoded sort order.
222       */
223      private static ASN1OctetString encodeControlValue(int targetPosition,
224                                          int contentCount, int vlvResultCode,
225                                          ByteString contextID)
226      {
227        ArrayList<ASN1Element> vlvElements = new ArrayList<ASN1Element>(4);
228        vlvElements.add(new ASN1Integer(targetPosition));
229        vlvElements.add(new ASN1Integer(contentCount));
230        vlvElements.add(new ASN1Enumerated(vlvResultCode));
231    
232        if (contextID != null)
233        {
234          vlvElements.add(contextID.toASN1OctetString());
235        }
236    
237        return new ASN1OctetString(new ASN1Sequence(vlvElements).encode());
238      }
239    
240    
241    
242      /**
243       * Creates a new VLV response control from the contents of the provided
244       * control.
245       *
246       * @param  control  The generic control containing the information to use to
247       *                  create this VLV response control.  It must not be
248       *                  {@code null}.
249       *
250       * @return  The VLV response control decoded from the provided control.
251       *
252       * @throws  LDAPException  If this control cannot be decoded as a valid VLV
253       *                         response control.
254       */
255      public static VLVResponseControl decodeControl(Control control)
256             throws LDAPException
257      {
258        ASN1OctetString controlValue = control.getValue();
259        if (controlValue == null)
260        {
261          Message message = INFO_VLVRES_CONTROL_NO_VALUE.get();
262          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
263        }
264    
265        try
266        {
267          ASN1Sequence vlvSequence =
268               ASN1Sequence.decodeAsSequence(controlValue.value());
269          ArrayList<ASN1Element> elements = vlvSequence.elements();
270    
271          if ((elements.size() < 3) || (elements.size() > 4))
272          {
273            Message message =
274                INFO_VLVRES_CONTROL_INVALID_ELEMENT_COUNT.get(elements.size());
275            throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
276          }
277    
278          int targetPosition = elements.get(0).decodeAsInteger().intValue();
279          int contentCount   = elements.get(1).decodeAsInteger().intValue();
280          int vlvResultCode  = elements.get(2).decodeAsEnumerated().intValue();
281    
282          ASN1OctetString contextID = null;
283          if (elements.size() == 4)
284          {
285            contextID = elements.get(3).decodeAsOctetString();
286          }
287    
288          return new VLVResponseControl(control.getOID(), control.isCritical(),
289                                        controlValue, targetPosition, contentCount,
290                                        vlvResultCode, contextID);
291        }
292        catch (LDAPException le)
293        {
294          throw le;
295        }
296        catch (Exception e)
297        {
298          Message message =
299              INFO_VLVRES_CONTROL_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
300          throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
301        }
302      }
303    
304    
305    
306      /**
307       * Retrieves a string representation of this VLV request control.
308       *
309       * @return  A string representation of this VLV request control.
310       */
311      public String toString()
312      {
313        StringBuilder buffer = new StringBuilder();
314        toString(buffer);
315        return buffer.toString();
316      }
317    
318    
319    
320      /**
321       * Appends a string representation of this VLV request control to the provided
322       * buffer.
323       *
324       * @param  buffer  The buffer to which the information should be appended.
325       */
326      public void toString(StringBuilder buffer)
327      {
328        buffer.append("VLVResponseControl(targetPosition=");
329        buffer.append(targetPosition);
330        buffer.append(", contentCount=");
331        buffer.append(contentCount);
332        buffer.append(", vlvResultCode=");
333        buffer.append(vlvResultCode);
334    
335        if (contextID != null)
336        {
337          buffer.append(", contextID=");
338          buffer.append(contextID);
339        }
340    
341        buffer.append(")");
342      }
343    }
344