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.shared.ldap.extras.controls.syncrepl_impl;
021
022
023import org.apache.directory.shared.asn1.DecoderException;
024import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
025import org.apache.directory.shared.asn1.ber.grammar.Grammar;
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.BooleanDecoder;
029import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
030import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
031import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
032import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
033import org.apache.directory.shared.asn1.ber.tlv.Value;
034import org.apache.directory.shared.i18n.I18n;
035import org.apache.directory.shared.ldap.extras.controls.SynchronizationModeEnum;
036import org.apache.directory.shared.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
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 instance = new SyncRequestValueGrammar();
070
071
072    /**
073     * Creates a new SyncRequestValueControlGrammar object.
074     */
075    private SyncRequestValueGrammar()
076    {
077        setName( SyncRequestValueGrammar.class.getName() );
078
079        // Create the transitions table
080        super.transitions = new GrammarTransition[SyncRequestValueStatesEnum.LAST_SYNC_REQUEST_VALUE_STATE.ordinal()][256];
081
082        /** 
083         * Transition from initial state to SyncRequestValue sequence
084         * SyncRequestValue ::= SEQUENCE OF {
085         *     ...
086         *     
087         * Initialize the syncRequestValue object
088         */
089        super.transitions[SyncRequestValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
090            new GrammarTransition( SyncRequestValueStatesEnum.START_STATE, 
091                                    SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE, 
092                                    UniversalTag.SEQUENCE.getValue(), 
093                null );
094
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.getValue()] = 
110            new GrammarTransition( SyncRequestValueStatesEnum.SYNC_REQUEST_VALUE_SEQUENCE_STATE, 
111                SyncRequestValueStatesEnum.MODE_STATE, 
112                UniversalTag.ENUMERATED.getValue(),
113                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl mode" )
114            {
115                public void action( SyncRequestValueContainer container ) throws DecoderException
116                {
117                    Value value = container.getCurrentTLV().getValue();
118
119                    try
120                    {
121                        // Check that the value is into the allowed interval
122                        int mode = IntegerDecoder.parse( value, 
123                            SynchronizationModeEnum.UNUSED.getValue(), 
124                            SynchronizationModeEnum.REFRESH_AND_PERSIST.getValue() );
125                        
126                        SynchronizationModeEnum modeEnum = SynchronizationModeEnum.getSyncMode( mode );
127                        
128                        if ( IS_DEBUG )
129                        {
130                            LOG.debug( "Mode = " + modeEnum );
131                        }
132
133                        container.getSyncRequestValueControl().setMode( modeEnum );
134
135                        // We can have an END transition
136                        container.setGrammarEndAllowed( true );
137                    }
138                    catch ( IntegerDecoderException e )
139                    {
140                        String msg = I18n.err( I18n.ERR_04028 );
141                        LOG.error( msg, e );
142                        throw new DecoderException( msg );
143                    }
144                }
145            } );
146
147
148        /** 
149         * Transition from mode to cookie
150         * SyncRequestValue ::= SEQUENCE OF {
151         *     ...
152         *     cookie     syncCookie OPTIONAL,
153         *     ...
154         *     
155         * Stores the cookie
156         */
157        super.transitions[SyncRequestValueStatesEnum.MODE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
158            new GrammarTransition( SyncRequestValueStatesEnum.MODE_STATE,
159                                    SyncRequestValueStatesEnum.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
160                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl cookie" )
161            {
162                public void action( SyncRequestValueContainer container ) throws DecoderException
163                {
164                    Value value = container.getCurrentTLV().getValue();
165
166                    byte[] cookie = value.getData();
167
168                    if ( IS_DEBUG )
169                    {
170                        LOG.debug( "cookie = " + Strings.dumpBytes(cookie) );
171                    }
172
173                    container.getSyncRequestValueControl().setCookie( cookie );
174
175                    // We can have an END transition
176                    container.setGrammarEndAllowed( true );
177                }
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( 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                    Value 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 e )
214                    {
215                        String msg = I18n.err( I18n.ERR_04029 );
216                        LOG.error( msg, e );
217                        throw new DecoderException( msg );
218                    }
219                }
220            } );
221
222
223        /** 
224         * Transition from cookie to reloadHint
225         * SyncRequestValue ::= SEQUENCE OF {
226         *     ...
227         *     reloadHint BOOLEAN DEFAULT FALSE
228         * }
229         *     
230         * Stores the reloadHint flag
231         */
232        super.transitions[SyncRequestValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = 
233            new GrammarTransition( SyncRequestValueStatesEnum.COOKIE_STATE,
234                                    SyncRequestValueStatesEnum.RELOAD_HINT_STATE, UniversalTag.BOOLEAN.getValue(),
235                new GrammarAction<SyncRequestValueContainer>( "Set SyncRequestValueControl reloadHint flag" )
236            {
237                public void action( SyncRequestValueContainer container ) throws DecoderException
238                {
239                    Value value = container.getCurrentTLV().getValue();
240
241                    try
242                    {
243                        boolean reloadHint = BooleanDecoder.parse( value );
244
245                        if ( IS_DEBUG )
246                        {
247                            LOG.debug( "reloadHint = " + reloadHint );
248                        }
249
250                        container.getSyncRequestValueControl().setReloadHint( reloadHint );
251
252                        // We can have an END transition
253                        container.setGrammarEndAllowed( true );
254                    }
255                    catch ( BooleanDecoderException e )
256                    {
257                        String msg = I18n.err( I18n.ERR_04029 );
258                        LOG.error( msg, e );
259                        throw new DecoderException( msg );
260                    }
261                }
262            } );
263    }
264
265
266    /**
267     * This class is a singleton.
268     * 
269     * @return An instance on this grammar
270     */
271    public static Grammar getInstance()
272    {
273        return instance;
274    }
275}