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