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 *    https://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 */
020package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
021
022
023import org.apache.directory.api.asn1.DecoderException;
024import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
025import org.apache.directory.api.asn1.ber.grammar.Grammar;
026import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
027import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
028import org.apache.directory.api.asn1.ber.tlv.BerValue;
029import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
030import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
031import org.apache.directory.api.i18n.I18n;
032import org.apache.directory.api.util.Strings;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.BOOLEAN;
037import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.OCTET_STRING;
038import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
039
040/**
041 * This class implements the EndTransactionRequest extended operation's ASN.1 grammar. 
042 * All the actions are declared in this class. As it is a singleton, 
043 * these declaration are only done once. The grammar is :
044 * 
045 * <pre>
046 * txnEndReq ::= SEQUENCE {
047 *         commit         BOOLEAN DEFAULT TRUE,
048 *         identifier     OCTET STRING }
049 * </pre>
050 * 
051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052 */
053
054public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransactionRequestContainer>
055{
056
057    /** logger */
058    private static final Logger LOG = LoggerFactory.getLogger( EndTransactionRequestGrammar.class );
059
060    /** The instance of grammar. EndTransactionRequestGrammar is a singleton */
061    private static Grammar<EndTransactionRequestContainer> instance = new EndTransactionRequestGrammar();
062
063
064    /**
065     * Creates a new EndTransactionRequestGrammar object.
066     */
067    @SuppressWarnings("unchecked")
068    public EndTransactionRequestGrammar()
069    {
070        setName( EndTransactionRequestGrammar.class.getName() );
071
072        // Create the transitions table
073        super.transitions = new GrammarTransition[EndTransactionRequestStates.LAST_STATE
074            .ordinal()][256];
075
076        /**
077         * Transition from init state to EndTransactionRequest Sequence
078         * 
079         *  txnEndReq ::= SEQUENCE {
080         *     ...
081         *     
082         * Creates the EndTransactionRequest object
083         */
084        super.transitions[EndTransactionRequestStates.START_STATE.ordinal()][SEQUENCE.getValue()] =
085            new GrammarTransition<EndTransactionRequestContainer>(
086                EndTransactionRequestStates.START_STATE,
087                EndTransactionRequestStates.SEQUENCE_STATE,
088                SEQUENCE, 
089                null );
090
091        /**
092         * Transition from Sequence to commit flag
093         *
094         * txnEndReq ::= SEQUENCE {
095         *         commit         BOOLEAN DEFAULT TRUE,
096         *     ...
097         *     
098         * Set the commit flag into the EndTransactionRequest instance.
099         */
100        super.transitions[EndTransactionRequestStates.SEQUENCE_STATE.ordinal()][BOOLEAN.getValue()] =
101            new GrammarTransition<EndTransactionRequestContainer>(
102                EndTransactionRequestStates.SEQUENCE_STATE,
103                EndTransactionRequestStates.COMMIT_STATE,
104                BOOLEAN,
105                new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest commit flag" )
106                {
107                    public void action( EndTransactionRequestContainer container ) throws DecoderException
108                    {
109                        BerValue value = container.getCurrentTLV().getValue();
110
111                        try
112                        {
113                            container.getEndTransactionRequest().setCommit( BooleanDecoder.parse( value ) );
114                        }
115                        catch ( BooleanDecoderException bde )
116                        {
117                            LOG.error( I18n
118                                .err( I18n.ERR_08221_BAD_END_TRANSACTION_COMMIT, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
119
120                            // This will generate a PROTOCOL_ERROR
121                            throw new DecoderException( bde.getMessage(), bde );
122                        }
123                    }
124                } );
125
126        /**
127         * Transition from Sequence to identifier
128         *
129         * txnEndReq ::= SEQUENCE {
130         *         identifier     OCTET STRING }
131         *     
132         * Set the commit flag into the EndTransactionRequest instance.
133         */
134        super.transitions[EndTransactionRequestStates.SEQUENCE_STATE.ordinal()][OCTET_STRING.getValue()] =
135            new GrammarTransition<EndTransactionRequestContainer>(
136                EndTransactionRequestStates.SEQUENCE_STATE,
137                EndTransactionRequestStates.IDENTFIER_STATE,
138                OCTET_STRING,
139                new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest identifier" )
140                {
141                    public void action( EndTransactionRequestContainer container )
142                    {
143                        BerValue value = container.getCurrentTLV().getValue();
144
145                        byte[] identifier = value.getData();
146
147                        if ( LOG.isDebugEnabled() )
148                        {
149                            LOG.debug( I18n.msg( I18n.MSG_08206_IDENTIFIER, Strings.dumpBytes( identifier ) ) );
150                        }
151
152                        if ( identifier == null )
153                        {
154                            identifier = Strings.EMPTY_BYTES;
155                        }
156
157                        container.getEndTransactionRequest().setTransactionId( identifier );
158
159                        // We may have nothing left
160                        container.setGrammarEndAllowed( true );
161                    }
162                } );
163
164        /**
165         * Transition from commit flag to identifier
166         *
167         * txnEndReq ::= SEQUENCE {
168         *         commit         BOOLEAN DEFAULT TRUE,
169         *         identifier     OCTET STRING }
170         *     
171         * Set the identifier into the EndTransactionRequest instance.
172         */
173        super.transitions[EndTransactionRequestStates.COMMIT_STATE.ordinal()][OCTET_STRING.getValue()] =
174            new GrammarTransition<EndTransactionRequestContainer>(
175                EndTransactionRequestStates.COMMIT_STATE,
176                EndTransactionRequestStates.IDENTFIER_STATE,
177                OCTET_STRING,
178                new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest identifier" )
179                {
180                    public void action( EndTransactionRequestContainer container )
181                    {
182                        BerValue value = container.getCurrentTLV().getValue();
183
184                        byte[] identifier = value.getData();
185
186                        if ( LOG.isDebugEnabled() )
187                        {
188                            LOG.debug( I18n.msg( I18n.MSG_08206_IDENTIFIER, Strings.dumpBytes( identifier ) ) );
189                        }
190
191                        if ( identifier == null )
192                        {
193                            identifier = Strings.EMPTY_BYTES;
194                        }
195
196                        container.getEndTransactionRequest().setTransactionId( identifier );
197
198                        // We may have nothing left
199                        container.setGrammarEndAllowed( true );
200                    }
201                } );
202    }
203
204
205    /**
206     * This class is a singleton.
207     * 
208     * @return An instance on this grammar
209     */
210    public static Grammar<EndTransactionRequestContainer> getInstance()
211    {
212        return instance;
213    }
214}