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