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 */
020package org.apache.directory.api.ldap.extras.extended.ads_impl.cancel;
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.IntegerDecoder;
030import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
031import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
032import org.apache.directory.api.i18n.I18n;
033import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
034import org.apache.directory.api.ldap.extras.extended.cancel.CancelRequestImpl;
035import org.apache.directory.api.util.Strings;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039
040/**
041 * This class implements the Cancel operation. All the actions are declared
042 * in this class. As it is a singleton, these declaration are only done once.
043 * The grammar is :
044 * 
045 * <pre>
046 *  cancelRequestValue ::= SEQUENCE {
047 *      cancelId     MessageID 
048 *                   -- MessageID is as defined in [RFC2251]
049 * }
050 * </pre>
051 * 
052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
053 */
054public final class CancelGrammar extends AbstractGrammar<CancelContainer>
055{
056    /** The logger */
057    static final Logger LOG = LoggerFactory.getLogger( CancelGrammar.class );
058
059    /** Speedup for logs */
060    static final boolean IS_DEBUG = LOG.isDebugEnabled();
061
062    /** The instance of grammar. CancelGrammar is a singleton */
063    private static Grammar<CancelContainer> instance = new CancelGrammar();
064
065
066    /**
067     * Creates a new GracefulDisconnectGrammar object.
068     */
069    @SuppressWarnings("unchecked")
070    private CancelGrammar()
071    {
072        setName( CancelGrammar.class.getName() );
073
074        // Create the transitions table
075        super.transitions = new GrammarTransition[CancelStatesEnum.LAST_CANCEL_STATE.ordinal()][256];
076
077        /**
078         * Transition from init state to cancel sequence
079         * cancelRequestValue ::= SEQUENCE {
080         *     ... 
081         * 
082         * Creates the Cancel object
083         */
084        super.transitions[CancelStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
085            new GrammarTransition<CancelContainer>( CancelStatesEnum.START_STATE,
086                CancelStatesEnum.CANCEL_SEQUENCE_STATE,
087                UniversalTag.SEQUENCE.getValue(),
088                new GrammarAction<CancelContainer>( "Init Cancel" )
089                {
090                    public void action( CancelContainer cancelContainer )
091                    {
092                        CancelRequestDecorator cancel = new CancelRequestDecorator(
093                            LdapApiServiceFactory.getSingleton(),
094                            new CancelRequestImpl() );
095
096                        cancelContainer.setCancel( cancel );
097                    }
098                } );
099
100        /**
101         * Transition from cancel SEQ to cancelId
102         * 
103         * cancelRequestValue ::= SEQUENCE {
104         *     cancelId   MessageID 
105         * }
106         *     
107         * Set the cancelId value into the Cancel object.    
108         */
109        super.transitions[CancelStatesEnum.CANCEL_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
110            new GrammarTransition<CancelContainer>( CancelStatesEnum.CANCEL_SEQUENCE_STATE,
111                CancelStatesEnum.CANCEL_ID_STATE,
112                UniversalTag.INTEGER.getValue(),
113                new GrammarAction<CancelContainer>( "Stores CancelId" )
114                {
115                    public void action( CancelContainer cancelContainer ) throws DecoderException
116                    {
117                        BerValue value = cancelContainer.getCurrentTLV().getValue();
118
119                        try
120                        {
121                            int cancelId = IntegerDecoder.parse( value, 0, Integer.MAX_VALUE );
122
123                            if ( IS_DEBUG )
124                            {
125                                LOG.debug( "CancelId = " + cancelId );
126                            }
127
128                            cancelContainer.getCancel().setCancelId( cancelId );
129                            cancelContainer.setGrammarEndAllowed( true );
130                        }
131                        catch ( IntegerDecoderException ide )
132                        {
133                            String msg = I18n.err( I18n.ERR_04031, Strings.dumpBytes( value.getData() ) );
134                            LOG.error( msg );
135                            throw new DecoderException( msg, ide );
136                        }
137                    }
138                } );
139    }
140
141
142    /**
143     * This class is a singleton.
144     * 
145     * @return An instance on this grammar
146     */
147    public static Grammar<CancelContainer> getInstance()
148    {
149        return instance;
150    }
151}