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 org.apache.directory.shared.asn1.ber.IAsn1Container;
024    import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
025    import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
026    import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
027    import org.apache.directory.shared.asn1.ber.grammar.IGrammar;
028    import org.apache.directory.shared.asn1.ber.grammar.IStates;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.DecoderException;
032    import org.apache.directory.shared.asn1.util.IntegerDecoder;
033    import org.apache.directory.shared.asn1.util.IntegerDecoderException;
034    import org.apache.directory.shared.i18n.I18n;
035    import org.apache.directory.shared.ldap.util.StringTools;
036    import org.slf4j.Logger;
037    import org.slf4j.LoggerFactory;
038    
039    
040    /**
041     * This class implements the PagedSearchControl. All the actions are declared in
042     * this class. As it is a singleton, these declaration are only done once.
043     * 
044     * The decoded grammar is the following :
045     * 
046     * realSearchControlValue ::= SEQUENCE {
047     *     size   INTEGER,
048     *     cookie OCTET STRING,
049     * }
050     * 
051     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052     * @version $Rev: 664290 $, $Date: 2008-06-07 08:28:06 +0200 (Sat, 07 Jun 2008) $, 
053     */
054    public class PagedResultsControlGrammar extends AbstractGrammar
055    {
056        /** The logger */
057        static final Logger log = LoggerFactory.getLogger( PagedResultsControlGrammar.class );
058    
059        /** Speedup for logs */
060        static final boolean IS_DEBUG = log.isDebugEnabled();
061    
062        /** The instance of grammar. PagedSearchControlGrammar is a singleton */
063        private static IGrammar instance = new PagedResultsControlGrammar();
064    
065    
066        /**
067         * Creates a new PagedSearchControlGrammar object.
068         */
069        private PagedResultsControlGrammar()
070        {
071            name = PagedResultsControlGrammar.class.getName();
072            statesEnum = PagedResultsControlStatesEnum.getInstance();
073    
074            // Create the transitions table
075            super.transitions = new GrammarTransition[PagedResultsControlStatesEnum.LAST_PAGED_SEARCH_STATE][256];
076    
077            /** 
078             * Transition from initial state to PagedSearch sequence
079             * realSearchControlValue ::= SEQUENCE OF {
080             *     ...
081             *     
082             * Nothing to do
083             */
084            super.transitions[IStates.INIT_GRAMMAR_STATE][UniversalTag.SEQUENCE_TAG] = 
085                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
086                                        PagedResultsControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE, 
087                                        UniversalTag.SEQUENCE_TAG, null );
088    
089    
090            /** 
091             * Transition from PagedSearch sequence to size
092             * 
093             * realSearchControlValue ::= SEQUENCE OF {
094             *     size  INTEGER,  -- INTEGER (0..maxInt),
095             *     ...
096             *     
097             * Stores the size value
098             */
099            super.transitions[PagedResultsControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE][UniversalTag.INTEGER_TAG] = 
100                new GrammarTransition( PagedResultsControlStatesEnum.PAGED_SEARCH_SEQUENCE_STATE, 
101                    PagedResultsControlStatesEnum.SIZE_STATE, 
102                    UniversalTag.INTEGER_TAG,
103                    new GrammarAction( "Set PagedSearchControl size" )
104                {
105                    public void action( IAsn1Container container ) throws DecoderException
106                    {
107                        PagedResultsControlContainer pagedSearchContainer = ( PagedResultsControlContainer ) container;
108                        Value value = pagedSearchContainer.getCurrentTLV().getValue();
109    
110                        try
111                        {
112                            // Check that the value is into the allowed interval
113                            int size = IntegerDecoder.parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE );
114                            
115                            // We allow negative value to absorb a bug in some M$ client.
116                            // Those negative values will be transformed to Integer.MAX_VALUE.
117                            if ( size < 0 )
118                            {
119                                size = Integer.MAX_VALUE;
120                            }
121                            
122                            if ( IS_DEBUG )
123                            {
124                                log.debug( "size = " + size );
125                            }
126    
127                            pagedSearchContainer.getPagedSearchControl().setSize( size );
128                        }
129                        catch ( IntegerDecoderException e )
130                        {
131                            String msg = I18n.err( I18n.ERR_04050 );
132                            log.error( msg, e );
133                            throw new DecoderException( msg );
134                        }
135                    }
136                } );
137    
138            /** 
139             * Transition from size to cookie
140             * realSearchControlValue ::= SEQUENCE OF {
141             *     ...
142             *     cookie   OCTET STRING
143             * }
144             *     
145             * Stores the cookie flag
146             */
147            super.transitions[PagedResultsControlStatesEnum.SIZE_STATE][UniversalTag.OCTET_STRING_TAG] = 
148                new GrammarTransition( PagedResultsControlStatesEnum.SIZE_STATE,
149                                        PagedResultsControlStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING_TAG,
150                    new GrammarAction( "Set PagedSearchControl cookie" )
151                {
152                    public void action( IAsn1Container container ) throws DecoderException
153                    {
154                        PagedResultsControlContainer pagedSearchContainer = ( PagedResultsControlContainer ) container;
155                        Value value = pagedSearchContainer.getCurrentTLV().getValue();
156    
157                        if ( pagedSearchContainer.getCurrentTLV().getLength() == 0 )
158                        {
159                            pagedSearchContainer.getPagedSearchControl().setCookie( StringTools.EMPTY_BYTES );
160                        }
161                        else
162                        {
163                            pagedSearchContainer.getPagedSearchControl().setCookie( value.getData() );
164                        }
165    
166                        // We can have an END transition
167                        pagedSearchContainer.grammarEndAllowed( true );
168                    }
169                } );
170        }
171    
172    
173        /**
174         * This class is a singleton.
175         * 
176         * @return An instance on this grammar
177         */
178        public static IGrammar getInstance()
179        {
180            return instance;
181        }
182    }