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 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.controls;
028    import org.opends.messages.Message;
029    
030    import static org.opends.server.loggers.debug.DebugLogger.*;
031    import org.opends.server.loggers.debug.DebugTracer;
032    import org.opends.server.types.DebugLogLevel;
033    import static org.opends.messages.ProtocolMessages.*;
034    import static org.opends.server.protocols.ldap.LDAPResultCode.PROTOCOL_ERROR;
035    import static org.opends.server.util.ServerConstants.OID_PAGED_RESULTS_CONTROL;
036    
037    import org.opends.server.protocols.asn1.ASN1Element;
038    import org.opends.server.protocols.asn1.ASN1Integer;
039    import org.opends.server.protocols.asn1.ASN1OctetString;
040    import org.opends.server.protocols.asn1.ASN1Sequence;
041    import org.opends.server.types.Control;
042    import org.opends.server.types.LDAPException;
043    
044    import java.util.ArrayList;
045    
046    /**
047     * This class represents a paged results control value as defined in
048     * RFC 2696.
049     *
050     * The searchControlValue is an OCTET STRING wrapping the BER-encoded
051     * version of the following SEQUENCE:
052     *
053     * realSearchControlValue ::= SEQUENCE {
054     *         size            INTEGER (0..maxInt),
055     *                                 -- requested page size from client
056     *                                 -- result set size estimate from server
057     *         cookie          OCTET STRING
058     * }
059     *
060     */
061    public class PagedResultsControl extends Control
062    {
063      /**
064       * The tracer object for the debug logger.
065       */
066      private static final DebugTracer TRACER = getTracer();
067    
068    
069    
070      /**
071       * The control value size element, which is either the requested page size
072       * from the client, or the result set size estimate from the server.
073       */
074      private int size;
075    
076    
077      /**
078       * The control value cookie element.
079       */
080      private ASN1OctetString cookie;
081    
082    
083      /**
084       * Creates a new paged results control with the specified information.
085       *
086       * @param  isCritical  Indicates whether this control should be considered
087       *                     critical in processing the request.
088       * @param  size        The size element.
089       * @param  cookie      The cookie element.
090       */
091      public PagedResultsControl(boolean isCritical, int size,
092                                 ASN1OctetString cookie)
093      {
094        super(OID_PAGED_RESULTS_CONTROL, isCritical);
095    
096    
097        this.size   = size;
098        this.cookie = cookie;
099    
100        this.setValue(encode());
101      }
102    
103    
104      /**
105       * Creates a new paged results control by decoding the given information.
106       *
107       * @param  isCritical  Indicates whether the control is considered
108       *                     critical in processing the request.
109       * @param  value       The value of the control.
110       *
111       * @throws  LDAPException  If a problem occurs while attempting to decode the
112       *                         provided information as a paged results control.
113       */
114      public PagedResultsControl(boolean isCritical, ASN1OctetString value)
115           throws LDAPException
116      {
117        super(OID_PAGED_RESULTS_CONTROL, isCritical, value);
118    
119        if (value == null)
120        {
121          Message message = ERR_LDAP_PAGED_RESULTS_DECODE_NULL.get();
122          throw new LDAPException(PROTOCOL_ERROR, message);
123        }
124    
125        ArrayList<ASN1Element> elements;
126        try
127        {
128          ASN1Element sequence = ASN1Element.decode(value.value());
129          elements = sequence.decodeAsSequence().elements();
130        }
131        catch (Exception e)
132        {
133          if (debugEnabled())
134          {
135            TRACER.debugCaught(DebugLogLevel.ERROR, e);
136          }
137    
138          Message message =
139              ERR_LDAP_PAGED_RESULTS_DECODE_SEQUENCE.get(String.valueOf(e));
140          throw new LDAPException(PROTOCOL_ERROR, message, e);
141        }
142    
143        int numElements = elements.size();
144        if (numElements != 2)
145        {
146          Message message =
147              ERR_LDAP_PAGED_RESULTS_DECODE_INVALID_ELEMENT_COUNT.get(numElements);
148          throw new LDAPException(PROTOCOL_ERROR, message);
149        }
150    
151        try
152        {
153          size = elements.get(0).decodeAsInteger().intValue();
154        }
155        catch (Exception e)
156        {
157          if (debugEnabled())
158          {
159            TRACER.debugCaught(DebugLogLevel.ERROR, e);
160          }
161    
162          Message message =
163              ERR_LDAP_PAGED_RESULTS_DECODE_SIZE.get(String.valueOf(e));
164          throw new LDAPException(PROTOCOL_ERROR, message, e);
165        }
166    
167        try
168        {
169          cookie = elements.get(1).decodeAsOctetString();
170        }
171        catch (Exception e)
172        {
173          if (debugEnabled())
174          {
175            TRACER.debugCaught(DebugLogLevel.ERROR, e);
176          }
177    
178          Message message =
179              ERR_LDAP_PAGED_RESULTS_DECODE_COOKIE.get(String.valueOf(e));
180          throw new LDAPException(PROTOCOL_ERROR, message, e);
181        }
182      }
183    
184    
185      /**
186       * Encodes this control value to an ASN.1 element.
187       *
188       * @return  The ASN.1 element containing the encoded control value.
189       */
190      public ASN1OctetString encode()
191      {
192        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
193        elements.add(new ASN1Integer(size));
194        elements.add(cookie);
195    
196        ASN1Sequence sequence = new ASN1Sequence(elements);
197        return new ASN1OctetString(sequence.encode());
198      }
199    
200    
201      /**
202       * Get the control value size element, which is either the requested page size
203       * from the client, or the result set size estimate from the server.
204       * @return The control value size element.
205       */
206      public int getSize()
207      {
208        return size;
209      }
210    
211    
212    
213      /**
214       * Get the control value cookie element.
215       * @return The control value cookie element.
216       */
217      public ASN1OctetString getCookie()
218      {
219        return cookie;
220      }
221    }