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.pSearch;
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.BooleanDecoder;
033    import org.apache.directory.shared.asn1.util.BooleanDecoderException;
034    import org.apache.directory.shared.asn1.util.IntegerDecoder;
035    import org.apache.directory.shared.asn1.util.IntegerDecoderException;
036    import org.slf4j.Logger;
037    import org.slf4j.LoggerFactory;
038    
039    
040    /**
041     * This class implements the PSearchControl. 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     * PersistenceSearch ::= SEQUENCE {
047     *     changeTypes  INTEGER,  -- an OR combinaison of 0, 1, 2 and 4 --
048     *     changeOnly   BOOLEAN,
049     *     returnECs    BOOLEAN
050     * }
051     * 
052     * The changeTypes field is the logical OR of one or more of these values:
053     * add    (1), 
054     * delete (2), 
055     * modify (4), 
056     * modDN  (8).
057     * 
058     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
059     * @version $Rev: 764131 $, $Date: 2009-04-11 03:03:00 +0200 (Sam, 11 avr 2009) $, 
060     */
061    public class PSearchControlGrammar extends AbstractGrammar
062    {
063        /** The logger */
064        static final Logger log = LoggerFactory.getLogger( PSearchControlGrammar.class );
065    
066        /** Speedup for logs */
067        static final boolean IS_DEBUG = log.isDebugEnabled();
068    
069        /** The instance of grammar. PSearchControlGrammar is a singleton */
070        private static IGrammar instance = new PSearchControlGrammar();
071    
072    
073        /**
074         * Creates a new PSearchControlGrammar object.
075         */
076        private PSearchControlGrammar()
077        {
078            name = PSearchControlGrammar.class.getName();
079            statesEnum = PSearchControlStatesEnum.getInstance();
080    
081            // Create the transitions table
082            super.transitions = new GrammarTransition[PSearchControlStatesEnum.LAST_PSEARCH_STATE][256];
083    
084            /** 
085             * Transition from initial state to Psearch sequence
086             * PSearch ::= SEQUENCE OF {
087             *     ...
088             *     
089             * Initialize the persistence search object
090             */
091            super.transitions[IStates.INIT_GRAMMAR_STATE][UniversalTag.SEQUENCE_TAG] = 
092                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
093                                        PSearchControlStatesEnum.PSEARCH_SEQUENCE_STATE, 
094                                        UniversalTag.SEQUENCE_TAG, 
095                    new GrammarAction( "Init PSearchControl" )
096                {
097                    public void action( IAsn1Container container )
098                    {
099                        PSearchControlContainer psearchContainer = ( PSearchControlContainer ) container;
100                        PSearchControlCodec control = new PSearchControlCodec();
101                        psearchContainer.setPSearchControl( control );
102                    }
103                } );
104    
105    
106            /** 
107             * Transition from Psearch sequence to Change types
108             * PSearch ::= SEQUENCE OF {
109             *     changeTypes  INTEGER,  -- an OR combinaison of 0, 1, 2 and 4 --
110             *     ...
111             *     
112             * Stores the change types value
113             */
114            super.transitions[PSearchControlStatesEnum.PSEARCH_SEQUENCE_STATE][UniversalTag.INTEGER_TAG] = 
115                new GrammarTransition( PSearchControlStatesEnum.PSEARCH_SEQUENCE_STATE, 
116                    PSearchControlStatesEnum.CHANGE_TYPES_STATE, 
117                    UniversalTag.INTEGER_TAG,
118                    new GrammarAction( "Set PSearchControl changeTypes" )
119                {
120                    public void action( IAsn1Container container ) throws DecoderException
121                    {
122                        PSearchControlContainer psearchContainer = ( PSearchControlContainer ) container;
123                        Value value = psearchContainer.getCurrentTLV().getValue();
124    
125                        try
126                        {
127                            // Check that the value is into the allowed interval
128                            int changeTypes = IntegerDecoder.parse( value, 
129                                PSearchControlCodec.CHANGE_TYPES_MIN, 
130                                PSearchControlCodec.CHANGE_TYPES_MAX );
131                            
132                            if ( IS_DEBUG )
133                            {
134                                log.debug( "changeTypes = " + changeTypes );
135                            }
136    
137                            psearchContainer.getPSearchControl().setChangeTypes( changeTypes );
138                        }
139                        catch ( IntegerDecoderException e )
140                        {
141                            String msg = "failed to decode the changeTypes for PSearchControl";
142                            log.error( msg, e );
143                            throw new DecoderException( msg );
144                        }
145                    }
146                } );
147    
148            /** 
149             * Transition from Change types to Changes only
150             * PSearch ::= SEQUENCE OF {
151             *     ...
152             *     changeOnly   BOOLEAN,
153             *     ...
154             *     
155             * Stores the change only flag
156             */
157            super.transitions[PSearchControlStatesEnum.CHANGE_TYPES_STATE][UniversalTag.BOOLEAN_TAG] = 
158                new GrammarTransition( PSearchControlStatesEnum.CHANGE_TYPES_STATE,
159                                        PSearchControlStatesEnum.CHANGES_ONLY_STATE, UniversalTag.BOOLEAN_TAG,
160                    new GrammarAction( "Set PSearchControl changesOnly" )
161                {
162                    public void action( IAsn1Container container ) throws DecoderException
163                    {
164                        PSearchControlContainer psearchContainer = ( PSearchControlContainer ) container;
165                        Value value = psearchContainer.getCurrentTLV().getValue();
166    
167                        try
168                        {
169                            boolean changesOnly = BooleanDecoder.parse( value );
170    
171                            if ( IS_DEBUG )
172                            {
173                                log.debug( "changesOnly = " + changesOnly );
174                            }
175    
176                            psearchContainer.getPSearchControl().setChangesOnly( changesOnly );
177                        }
178                        catch ( BooleanDecoderException e )
179                        {
180                            String msg = "failed to decode the changesOnly for PSearchControl";
181                            log.error( msg, e );
182                            throw new DecoderException( msg );
183                        }
184                    }
185                } );
186    
187            /** 
188             * Transition from Change types to Changes only
189             * PSearch ::= SEQUENCE OF {
190             *     ...
191             *     returnECs    BOOLEAN 
192             * }
193             *     
194             * Stores the return ECs flag 
195             */
196            super.transitions[PSearchControlStatesEnum.CHANGES_ONLY_STATE][UniversalTag.BOOLEAN_TAG] = 
197                new GrammarTransition( PSearchControlStatesEnum.CHANGES_ONLY_STATE, 
198                                        PSearchControlStatesEnum.RETURN_ECS_STATE, UniversalTag.BOOLEAN_TAG,
199                    new GrammarAction( "Set PSearchControl returnECs" )
200                {
201                    public void action( IAsn1Container container ) throws DecoderException
202                    {
203                        PSearchControlContainer psearchContainer = ( PSearchControlContainer ) container;
204                        Value value = psearchContainer.getCurrentTLV().getValue();
205    
206                        try
207                        {
208                            boolean returnECs = BooleanDecoder.parse( value );
209    
210                            if ( IS_DEBUG )
211                            {
212                                log.debug( "returnECs = " + returnECs );
213                            }
214    
215                            psearchContainer.getPSearchControl().setReturnECs( returnECs );
216    
217                            // We can have an END transition
218                            psearchContainer.grammarEndAllowed( true );
219                        }
220                        catch ( BooleanDecoderException e )
221                        {
222                            String msg = "failed to decode the returnECs for PSearchControl";
223                            log.error( msg, e );
224                            throw new DecoderException( msg );
225                        }
226                    }
227                } );
228        }
229    
230    
231        /**
232         * This class is a singleton.
233         * 
234         * @return An instance on this grammar
235         */
236        public static IGrammar getInstance()
237        {
238            return instance;
239        }
240    }