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    
021    package org.apache.directory.shared.ldap.codec.extended.operations.storedProcedure;
022    
023    
024    import org.apache.directory.shared.asn1.ber.IAsn1Container;
025    import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
026    import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
027    import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
028    import org.apache.directory.shared.asn1.ber.grammar.IGrammar;
029    import org.apache.directory.shared.asn1.ber.tlv.TLV;
030    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031    import org.apache.directory.shared.asn1.codec.DecoderException;
032    import org.apache.directory.shared.i18n.I18n;
033    import org.apache.directory.shared.ldap.codec.extended.operations.storedProcedure.StoredProcedure.StoredProcedureParameter;
034    import org.apache.directory.shared.ldap.util.StringTools;
035    import org.slf4j.Logger;
036    import org.slf4j.LoggerFactory;
037    
038    
039    /**
040     * ASN.1 BER Grammar for Stored Procedure Extended Operation
041     * 
042     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
043     * @version $Rev$, $Date$, 
044     */
045    public class StoredProcedureGrammar extends AbstractGrammar
046    {
047        //~ Static fields/initializers -----------------------------------------------------------------
048    
049        /** The logger */
050        //private static final Logger log = LoggerFactory.getLogger( StoredProcedureGrammar.class );
051        static final Logger log = LoggerFactory.getLogger( StoredProcedureGrammar.class );
052    
053        /** The instance of grammar. StoredProcedureGrammar is a singleton. */
054        private static IGrammar instance = new StoredProcedureGrammar();
055    
056    
057        //~ Constructors -------------------------------------------------------------------------------
058    
059        /**
060         * Creates a new StoredProcedureGrammar object.
061         */
062        private StoredProcedureGrammar()
063        {
064            name = StoredProcedureGrammar.class.getName();
065            statesEnum = StoredProcedureStatesEnum.getInstance();
066    
067            // Create the transitions table
068            super.transitions = new GrammarTransition[StoredProcedureStatesEnum.LAST_STORED_PROCEDURE_STATE][256];
069    
070            //============================================================================================
071            // StoredProcedure Message
072            //============================================================================================
073            // StoredProcedure ::= SEQUENCE {
074            //   ...
075            // Nothing to do.
076            super.transitions[StoredProcedureStatesEnum.START_STATE][UniversalTag.SEQUENCE_TAG] = 
077                new GrammarTransition( StoredProcedureStatesEnum.START_STATE, 
078                                        StoredProcedureStatesEnum.STORED_PROCEDURE_STATE, 
079                                        UniversalTag.SEQUENCE_TAG, 
080                                        null );
081    
082            //    language OCTETSTRING, (Tag)
083            //    ...
084            //
085            // Creates the storeProcedure and stores the language
086            super.transitions[StoredProcedureStatesEnum.STORED_PROCEDURE_STATE][UniversalTag.OCTET_STRING_TAG] = 
087                new GrammarTransition( StoredProcedureStatesEnum.STORED_PROCEDURE_STATE, 
088                                        StoredProcedureStatesEnum.LANGUAGE_STATE, 
089                                        UniversalTag.OCTET_STRING_TAG,
090                    new GrammarAction( "Stores the language" )
091                {
092                    public void action( IAsn1Container container ) throws DecoderException
093                    {
094    
095                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
096    
097                        TLV tlv = storedProcedureContainer.getCurrentTLV();
098    
099                        StoredProcedure storedProcedure = null;
100    
101                        // Store the value.
102                        if ( tlv.getLength() == 0 )
103                        {
104                            // We can't have a void language !
105                            log.error( I18n.err( I18n.ERR_04038 ) );
106                            throw new DecoderException( I18n.err( I18n.ERR_04038 ) );
107                        }
108                        else
109                        {
110                            // Only this field's type is String by default
111                            String language = StringTools.utf8ToString( tlv.getValue().getData() );
112    
113                            if ( log.isDebugEnabled() )
114                            {
115                                log.debug( "SP language found: " + language );
116                            }
117    
118                            storedProcedure = new StoredProcedure();
119                            storedProcedure.setLanguage( language );
120                            storedProcedureContainer.setStoredProcedure( storedProcedure );
121                        }
122                    }
123                } );
124    
125            //    procedure OCTETSTRING, (Value)
126            //    ...
127            // Stores the procedure.
128            super.transitions[StoredProcedureStatesEnum.LANGUAGE_STATE][UniversalTag.OCTET_STRING_TAG] = 
129                new GrammarTransition( StoredProcedureStatesEnum.LANGUAGE_STATE, 
130                                        StoredProcedureStatesEnum.PROCEDURE_STATE, 
131                                        UniversalTag.OCTET_STRING_TAG,
132                    new GrammarAction(
133                    "Stores the procedure" )
134                {
135                    public void action( IAsn1Container container ) throws DecoderException
136                    {
137    
138                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
139    
140                        TLV tlv = storedProcedureContainer.getCurrentTLV();
141    
142                        StoredProcedure storedProcedure = storedProcedureContainer.getStoredProcedure();
143    
144                        // Store the value.
145                        if ( tlv.getLength() == 0 )
146                        {
147                            // We can't have a void procedure !
148                            log.error( I18n.err( I18n.ERR_04039 ) );
149                            throw new DecoderException( I18n.err( I18n.ERR_04039 ) );
150                        }
151                        else
152                        {
153                            byte[] procedure = tlv.getValue().getData();
154    
155                            storedProcedure.setProcedure( procedure );
156                        }
157    
158                        if ( log.isDebugEnabled() )
159                        {
160                            log.debug( "Procedure found : " + StringTools.utf8ToString( storedProcedure.getProcedure() ) );
161                        }
162                    }
163                } );
164    
165            // parameters SEQUENCE OF Parameter { (Value)
166            //    ...
167            // The list of parameters will be created with the first parameter.
168            // We can have an empty list of parameters, so the PDU can be empty
169            super.transitions[StoredProcedureStatesEnum.PROCEDURE_STATE][UniversalTag.SEQUENCE_TAG] = 
170                new GrammarTransition( StoredProcedureStatesEnum.PROCEDURE_STATE, 
171                                        StoredProcedureStatesEnum.PARAMETERS_STATE, 
172                                        UniversalTag.SEQUENCE_TAG, 
173                new GrammarAction(
174                    "Stores the parameters" )
175                {
176                    public void action( IAsn1Container container ) throws DecoderException
177                    {
178                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
179                        storedProcedureContainer.grammarEndAllowed( true );
180                    }
181                } );
182            
183            // parameter SEQUENCE OF { (Value)
184            //    ...
185            // Nothing to do. 
186            super.transitions[StoredProcedureStatesEnum.PARAMETERS_STATE][UniversalTag.SEQUENCE_TAG] = 
187                new GrammarTransition( StoredProcedureStatesEnum.PARAMETERS_STATE, 
188                                        StoredProcedureStatesEnum.PARAMETER_STATE, 
189                                        UniversalTag.SEQUENCE_TAG, 
190                                        null );
191    
192            // Parameter ::= {
193            //    type OCTETSTRING, (Value)
194            //    ...
195            //
196            // We can create a parameter, and store its type
197            super.transitions[StoredProcedureStatesEnum.PARAMETER_STATE][UniversalTag.OCTET_STRING_TAG] = 
198                new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_STATE, 
199                                        StoredProcedureStatesEnum.PARAMETER_TYPE_STATE, 
200                                        UniversalTag.OCTET_STRING_TAG,
201                    new GrammarAction( "Store parameter type" )
202                {
203                    public void action( IAsn1Container container ) throws DecoderException
204                    {
205                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
206    
207                        TLV tlv = storedProcedureContainer.getCurrentTLV();
208                        StoredProcedure storedProcedure = storedProcedureContainer.getStoredProcedure();
209    
210                        // Store the value.
211                        if ( tlv.getLength() == 0 )
212                        {
213                            // We can't have a void parameter type !
214                            log.error( I18n.err( I18n.ERR_04040 ) );
215                            throw new DecoderException( I18n.err( I18n.ERR_04040 ) );
216                        }
217                        else
218                        {
219                            StoredProcedureParameter parameter = new StoredProcedureParameter();
220    
221                            byte[] parameterType = tlv.getValue().getData();
222    
223                            parameter.setType( parameterType );
224    
225                            // We store the type in the current parameter.
226                            storedProcedure.setCurrentParameter( parameter );
227    
228                            if ( log.isDebugEnabled() )
229                            {
230                                log.debug( "Parameter type found : " + StringTools.dumpBytes( parameterType ) );
231                            }
232    
233                        }
234                    }
235                } );
236    
237            // Parameter ::= {
238            //    ...
239            //    value OCTETSTRING (Tag)
240            // }
241            // Store the parameter value
242            super.transitions[StoredProcedureStatesEnum.PARAMETER_TYPE_STATE][UniversalTag.OCTET_STRING_TAG] = 
243                new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_TYPE_STATE, 
244                                        StoredProcedureStatesEnum.PARAMETER_VALUE_STATE, 
245                                        UniversalTag.OCTET_STRING_TAG,
246                    new GrammarAction( "Store parameter value" )
247                {
248                    public void action( IAsn1Container container ) throws DecoderException
249                    {
250                        StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
251    
252                        TLV tlv = storedProcedureContainer.getCurrentTLV();
253                        StoredProcedure storedProcedure = storedProcedureContainer.getStoredProcedure();
254    
255                        // Store the value.
256                        if ( tlv.getLength() == 0 )
257                        {
258                            // We can't have a void parameter value !
259                            log.error( I18n.err( I18n.ERR_04041 ) );
260                            throw new DecoderException( I18n.err( I18n.ERR_04041 ) );
261                        }
262                        else
263                        {
264                            byte[] parameterValue = tlv.getValue().getData();
265    
266                            if ( parameterValue.length != 0 )
267                            {
268                                StoredProcedureParameter parameter = storedProcedure.getCurrentParameter();
269                                parameter.setValue( parameterValue );
270    
271                                // We can now add a new Parameter to the procedure
272                                storedProcedure.addParameter( parameter );
273    
274                                if ( log.isDebugEnabled() )
275                                {
276                                    log.debug( "Parameter value found : " + StringTools.dumpBytes( parameterValue ) );
277                                }
278                            }
279                            else
280                            {
281                                log.error( I18n.err( I18n.ERR_04042 ) );
282                                throw new DecoderException( I18n.err( I18n.ERR_04042 ) );
283                            }
284                        }
285    
286                        // The only possible END state for the grammar is here
287                        container.grammarEndAllowed( true );
288                    }
289                } );
290            
291            // Parameters ::= SEQUENCE OF Parameter
292            // 
293            // Loop on next parameter
294            super.transitions[StoredProcedureStatesEnum.PARAMETER_VALUE_STATE][UniversalTag.SEQUENCE_TAG] = 
295                new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_VALUE_STATE, 
296                                        StoredProcedureStatesEnum.PARAMETER_STATE, 
297                                        UniversalTag.SEQUENCE_TAG,
298                                        null );
299        }
300    
301    
302        //~ Methods ------------------------------------------------------------------------------------
303    
304        /**
305         * Get the instance of this grammar
306         *
307         * @return An instance on the StoredProcedure Grammar
308         */
309        public static IGrammar getInstance()
310        {
311            return instance;
312        }
313    }