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 */
020package org.apache.directory.api.ldap.model.message.controls;
021
022
023import org.apache.directory.api.util.StringConstants;
024import org.apache.directory.api.util.Strings;
025
026import java.util.Arrays;
027
028
029/**
030 * A request/response control used to implement a simple paging of search
031 * results. This is an implementation of RFC 2696 :
032 * <a href="http://www.faqs.org/rfcs/rfc2696.html">LDAP Control Extension for Simple Paged Results Manipulation</a>
033 * <br>
034 * <pre>
035 *    This control is included in the searchRequest and searchResultDone
036 *    messages as part of the controls field of the LDAPMessage, as defined
037 *    in Section 4.1.12 of [LDAPv3]. The structure of this control is as
038 *    follows:
039 *
040 * pagedResultsControl ::= SEQUENCE {
041 *         controlType     1.2.840.113556.1.4.319,
042 *         criticality     BOOLEAN DEFAULT FALSE,
043 *         controlValue    searchControlValue
044 * }
045 * 
046 * The searchControlValue is an OCTET STRING wrapping the BER-encoded
047 * version of the following SEQUENCE:
048 * 
049 * realSearchControlValue ::= SEQUENCE {
050 *         size            INTEGER (0..maxInt),
051 *                                 -- requested page size from client
052 *                                 -- result set size estimate from server
053 *         cookie          OCTET STRING
054 * }
055 * 
056 * </pre>
057 * 
058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
059 */
060public class PagedResultsImpl extends AbstractControl implements PagedResults
061{
062    /** The number of entries to return, or returned */
063    private int size;
064
065    /** The exchanged cookie */
066    private byte[] cookie = StringConstants.EMPTY_BYTES;
067
068
069    /**
070     * Creates a new instance of PagedResultsDecorator.
071     */
072    public PagedResultsImpl()
073    {
074        super( OID );
075    }
076
077
078    public int getSize()
079    {
080        return size;
081    }
082
083
084    public void setSize( int size )
085    {
086        this.size = size;
087    }
088
089
090    public byte[] getCookie()
091    {
092        return cookie;
093    }
094
095
096    public void setCookie( byte[] cookie )
097    {
098        this.cookie = cookie;
099    }
100
101
102    public int getCookieValue()
103    {
104        int value = 0;
105
106        switch ( cookie.length )
107        {
108            case 1:
109                value = cookie[0] & 0x00FF;
110                break;
111
112            case 2:
113                value = ( ( cookie[0] & 0x00FF ) << 8 ) + ( cookie[1] & 0x00FF );
114                break;
115
116            case 3:
117                value = ( ( cookie[0] & 0x00FF ) << 16 ) + ( ( cookie[1] & 0x00FF ) << 8 ) + ( cookie[2] & 0x00FF );
118                break;
119
120            case 4:
121                value = ( ( cookie[0] & 0x00FF ) << 24 ) + ( ( cookie[1] & 0x00FF ) << 16 )
122                    + ( ( cookie[2] & 0x00FF ) << 8 ) + ( cookie[3] & 0x00FF );
123                break;
124
125            default:
126                break;
127        }
128
129        return value;
130    }
131
132
133    /**
134     * @see Object#hashCode()
135     */
136    @Override
137    public int hashCode()
138    {
139        int h = super.hashCode();
140
141        h = h * 37 + size;
142
143        if ( cookie != null )
144        {
145            for ( byte b : cookie )
146            {
147                h = h * 17 + b;
148            }
149        }
150
151        return h;
152    }
153
154
155    /**
156     * @see Object#equals(Object)
157     */
158    @Override
159    public boolean equals( Object o )
160    {
161        if ( !super.equals( o ) )
162        {
163            return false;
164        }
165
166        PagedResults otherControl = ( PagedResults ) o;
167
168        return ( size == otherControl.getSize() ) && Arrays.equals( cookie, otherControl.getCookie() );
169    }
170
171
172    /**
173     * Return a String representing this PagedSearchControl.
174     */
175    public String toString()
176    {
177        StringBuffer sb = new StringBuffer();
178
179        sb.append( "    Paged Search Control\n" );
180        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
181        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
182        sb.append( "        size   : '" ).append( size ).append( "'\n" );
183        sb.append( "        cookie   : '" ).append( Strings.dumpBytes( cookie ) ).append( "'\n" );
184
185        return sb.toString();
186    }
187}