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.controls.syncrepl_impl;
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.asn1.ber.tlv.IntegerDecoder;
032import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
033import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
034import org.apache.directory.api.i18n.I18n;
035import org.apache.directory.api.ldap.extras.controls.SynchronizationModeEnum;
036import org.apache.directory.api.util.Strings;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * This class implements the SyncRequestValueControl. All the actions are declared in
043 * this class. As it is a singleton, these declaration are only done once.
044 * 
045 * The decoded grammar is the following :
046 * 
047 * syncRequestValue ::= SEQUENCE {
048 *     mode ENUMERATED {
049 *     -- 0 unused
050 *     refreshOnly       (1),
051 *     -- 2 reserved
052 *     refreshAndPersist (3)
053 *     },
054 *     cookie     syncCookie OPTIONAL,
055 *     reloadHint BOOLEAN DEFAULT FALSE
056 * }
057 * 
058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
059 */
060public final class SyncRequestValueGrammar extends AbstractGrammar<SyncRequestValueContainer>
061{
062    /** The logger */
063    static final Logger LOG = LoggerFactory.getLogger( SyncRequestValueGrammar.class );
064
065    /** Speedup for logs */
066    static final boolean IS_DEBUG = LOG.isDebugEnabled();
067
068    /** The instance of grammar. SyncRequestValueControlGrammar is a singleton */
069    private static Grammar<SyncRequestValueContainer> instance = new SyncRequestValueGrammar();
070
071
072    /**
073     * Creates a new SyncRequestValueControlGrammar object.
074     */
075    @SuppressWarnings("unchecked")
076    private SyncRequestValueGrammar()
077    {
078        setName( SyncRequestValueGrammar.class.getName() );
079
080        // Create the transitions table
081        super.transitions = new GrammarTransition[SyncRequestValueStatesEnum.LAST_SYNC_REQUEST_VALUE_STATE.ordinal()][256];
082
083        /** 
084         * Transition from initial state to SyncRequestValue sequence
085         * SyncRequestValue ::= SEQUENCE OF {
086         *     ...
087         *     
088         * Initialize the syncRequestValue object
089         */
090        super.transitions[SyncRequestValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
091            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.START_STATE,
092                SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE,
093                UniversalTag.SEQUENCE.getValue(),
094                null );
095
096        /** 
097         * Transition from SyncRequestValue sequence to Change types
098         * SyncRequestValue ::= SEQUENCE OF {
099         *     mode ENUMERATED {
100         *         -- 0 unused
101         *         refreshOnly       (1),
102         *         -- 2 reserved
103         *         refreshAndPersist (3)
104         *     },
105         *     ...
106         *     
107         * Stores the mode value
108         */
109        super.transitions[SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED
110            .getValue()] =
111            new GrammarTransition<SyncRequestValueContainer>(
112                SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE,
113                SyncRequestValueStatesEnum.MODE_STATE,
114                UniversalTag.ENUMERATED.getValue(),
115                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl mode" )
116                {
117                    public void action( SyncRequestValueContainer container ) throws DecoderException
118                    {
119                        BerValue value = container.getCurrentTLV().getValue();
120
121                        try
122                        {
123                            // Check that the value is into the allowed interval
124                            int mode = IntegerDecoder.parse( value,
125                                SynchronizationModeEnum.UNUSED.getValue(),
126                                SynchronizationModeEnum.REFRESH_AND_PERSIST.getValue() );
127
128                            SynchronizationModeEnum modeEnum = SynchronizationModeEnum.getSyncMode( mode );
129
130                            if ( IS_DEBUG )
131                            {
132                                LOG.debug( "Mode = " + modeEnum );
133                            }
134
135                            container.getSyncRequestValueControl().setMode( modeEnum );
136
137                            // We can have an END transition
138                            container.setGrammarEndAllowed( true );
139                        }
140                        catch ( IntegerDecoderException ide )
141                        {
142                            String msg = I18n.err( I18n.ERR_04028 );
143                            LOG.error( msg, ide );
144                            throw new DecoderException( msg, ide );
145                        }
146                    }
147                } );
148
149        /** 
150         * Transition from mode to cookie
151         * SyncRequestValue ::= SEQUENCE OF {
152         *     ...
153         *     cookie     syncCookie OPTIONAL,
154         *     ...
155         *     
156         * Stores the cookie
157         */
158        super.transitions[SyncRequestValueStatesEnum.MODE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
159            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.MODE_STATE,
160                SyncRequestValueStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
161                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl cookie" )
162                {
163                    public void action( SyncRequestValueContainer container ) throws DecoderException
164                    {
165                        BerValue value = container.getCurrentTLV().getValue();
166
167                        byte[] cookie = value.getData();
168
169                        if ( IS_DEBUG )
170                        {
171                            LOG.debug( "cookie = " + Strings.dumpBytes( cookie ) );
172                        }
173
174                        container.getSyncRequestValueControl().setCookie( cookie );
175
176                        // We can have an END transition
177                        container.setGrammarEndAllowed( true );
178                    }
179                } );
180
181        /** 
182         * Transition from mode to reloadHint
183         * SyncRequestValue ::= SEQUENCE OF {
184         *     ...
185         *     reloadHint BOOLEAN DEFAULT FALSE
186         * }
187         *     
188         * Stores the reloadHint flag
189         */
190        super.transitions[SyncRequestValueStatesEnum.MODE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
191            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.MODE_STATE,
192                SyncRequestValueStatesEnum.RELOAD_HINT_STATE, UniversalTag.BOOLEAN.getValue(),
193                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl reloadHint flag" )
194                {
195                    public void action( SyncRequestValueContainer container ) throws DecoderException
196                    {
197                        BerValue value = container.getCurrentTLV().getValue();
198
199                        try
200                        {
201                            boolean reloadHint = BooleanDecoder.parse( value );
202
203                            if ( IS_DEBUG )
204                            {
205                                LOG.debug( "reloadHint = " + reloadHint );
206                            }
207
208                            container.getSyncRequestValueControl().setReloadHint( reloadHint );
209
210                            // We can have an END transition
211                            container.setGrammarEndAllowed( true );
212                        }
213                        catch ( BooleanDecoderException bde )
214                        {
215                            String msg = I18n.err( I18n.ERR_04029 );
216                            LOG.error( msg, bde );
217                            throw new DecoderException( msg, bde );
218                        }
219                    }
220                } );
221
222        /** 
223         * Transition from cookie to reloadHint
224         * SyncRequestValue ::= SEQUENCE OF {
225         *     ...
226         *     reloadHint BOOLEAN DEFAULT FALSE
227         * }
228         *     
229         * Stores the reloadHint flag
230         */
231        super.transitions[SyncRequestValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
232            new GrammarTransition<SyncRequestValueContainer>( SyncRequestValueStatesEnum.COOKIE_STATE,
233                SyncRequestValueStatesEnum.RELOAD_HINT_STATE, UniversalTag.BOOLEAN.getValue(),
234                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl reloadHint flag" )
235                {
236                    public void action( SyncRequestValueContainer container ) throws DecoderException
237                    {
238                        BerValue value = container.getCurrentTLV().getValue();
239
240                        try
241                        {
242                            boolean reloadHint = BooleanDecoder.parse( value );
243
244                            if ( IS_DEBUG )
245                            {
246                                LOG.debug( "reloadHint = " + reloadHint );
247                            }
248
249                            container.getSyncRequestValueControl().setReloadHint( reloadHint );
250
251                            // We can have an END transition
252                            container.setGrammarEndAllowed( true );
253                        }
254                        catch ( BooleanDecoderException bde )
255                        {
256                            String msg = I18n.err( I18n.ERR_04029 );
257                            LOG.error( msg, bde );
258                            throw new DecoderException( msg, bde );
259                        }
260                    }
261                } );
262    }
263
264
265    /**
266     * This class is a singleton.
267     * 
268     * @return An instance on this grammar
269     */
270    public static Grammar<SyncRequestValueContainer> getInstance()
271    {
272        return instance;
273    }
274}