001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.codec.search.controls.pagedSearch;
021    
022    
023    import java.nio.ByteBuffer;
024    
025    import org.apache.directory.shared.asn1.AbstractAsn1Object;
026    import org.apache.directory.shared.asn1.ber.tlv.TLV;
027    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
028    import org.apache.directory.shared.asn1.ber.tlv.Value;
029    import org.apache.directory.shared.asn1.codec.EncoderException;
030    import org.apache.directory.shared.ldap.util.StringTools;
031    
032    
033    /**
034     * A request/response control used to implement a simple paging of search
035     * results. This is an implementation of RFC 2696 :
036     * <a href="http://www.faqs.org/rfcs/rfc2696.html">LDAP Control Extension for Simple Paged Results Manipulation</a>
037     * <br/>
038     * <pre>
039     *    This control is included in the searchRequest and searchResultDone
040     *    messages as part of the controls field of the LDAPMessage, as defined
041     *    in Section 4.1.12 of [LDAPv3]. The structure of this control is as
042     *    follows:
043     *
044     * pagedResultsControl ::= SEQUENCE {
045     *         controlType     1.2.840.113556.1.4.319,
046     *         criticality     BOOLEAN DEFAULT FALSE,
047     *         controlValue    searchControlValue
048     * }
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     * </pre>
061     * 
062     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
063     * @version $Rev:  $
064     */
065    public class PagedSearchControlCodec extends AbstractAsn1Object
066    {
067        /** The number of entries to return, or returned */
068        private int size;
069        
070        /** The exchanged cookie */
071        private byte[] cookie;
072    
073        /** The entry change global length */
074        private int pscSeqLength;
075    
076    
077        /**
078         * @see Asn1Object#Asn1Object
079         */
080        public PagedSearchControlCodec()
081        {
082            super();
083        }
084    
085        
086        /**
087         * Compute the PagedSearchControl length 
088         * 
089         * 0x30 L1 
090         *   | 
091         *   +--> 0x02 0x0(1-4) [0..2^63-1] (size) 
092         *   +--> 0x04 L2 (cookie) 
093         */
094        public int computeLength()
095        {
096            int sizeLength = 1 + 1 + Value.getNbBytes( size );;
097    
098            int cookieLength = 0;
099            
100            if ( cookie != null )
101            {
102                cookieLength = 1 + TLV.getNbBytes( cookie.length ) + cookie.length;
103            }
104            else
105            {
106                cookieLength = 1 + 1;
107            }
108    
109            pscSeqLength = sizeLength + cookieLength;
110    
111            return 1 + TLV.getNbBytes( pscSeqLength ) + pscSeqLength;
112        }
113    
114    
115        /**
116         * Encodes the paged search control.
117         * 
118         * @param buffer The encoded sink
119         * @return A ByteBuffer that contains the encoded PDU
120         * @throws EncoderException If anything goes wrong.
121         */
122        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
123        {
124            // Allocate the bytes buffer.
125            ByteBuffer bb = ByteBuffer.allocate( computeLength() );
126            bb.put( UniversalTag.SEQUENCE_TAG );
127            bb.put( TLV.getBytes( pscSeqLength ) );
128    
129            Value.encode( bb, size );
130            Value.encode( bb, cookie );
131            
132            return bb;
133        }
134    
135    
136        /**
137         * Return a String representing this PagedSearchControl.
138         */
139        public String toString()
140        {
141            StringBuffer sb = new StringBuffer();
142    
143            sb.append( "    Paged Search Control\n" );
144            sb.append( "        size   : '" ).append( size ).append( "'\n" );
145            sb.append( "        cookie   : '" ).append( StringTools.dumpBytes( cookie ) ).append( "'\n" );
146            
147            return sb.toString();
148        }
149    
150    
151        /**
152         * @return The requested or returned number of entries
153         */
154        public int getSize()
155        {
156            return size;
157        }
158    
159    
160        /**
161         * Set the number of entry requested or returned
162         *
163         * @param size The number of entries 
164         */
165        public void setSize( int size )
166        {
167            this.size = size;
168        }
169    
170    
171        /**
172         * @return The stored cookie
173         */
174        public byte[] getCookie()
175        {
176            return cookie;
177        }
178    
179    
180        /**
181         * Set the cookie
182         *
183         * @param cookie The cookie to store in this control
184         */
185        public void setCookie( byte[] cookie )
186        {
187            this.cookie = cookie;
188        }
189    }