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