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    package org.apache.directory.shared.ldap.codec.extended.operations.gracefulDisconnect;
021    
022    
023    import org.apache.directory.shared.asn1.ber.IAsn1Container;
024    import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
025    import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
026    import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
027    import org.apache.directory.shared.asn1.ber.grammar.IGrammar;
028    import org.apache.directory.shared.asn1.ber.grammar.IStates;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.DecoderException;
032    import org.apache.directory.shared.asn1.util.IntegerDecoder;
033    import org.apache.directory.shared.asn1.util.IntegerDecoderException;
034    import org.apache.directory.shared.i18n.I18n;
035    import org.apache.directory.shared.ldap.codec.extended.operations.GracefulActionConstants;
036    import org.apache.directory.shared.ldap.codec.util.LdapURLEncodingException;
037    import org.apache.directory.shared.ldap.util.LdapURL;
038    import org.apache.directory.shared.ldap.util.StringTools;
039    import org.slf4j.Logger;
040    import org.slf4j.LoggerFactory;
041    
042    
043    /**
044     * This class implements the Graceful Disconnect. All the actions are declared
045     * in this class. As it is a singleton, these declaration are only done once.
046     * The grammar is :
047     * 
048     * <pre>
049     *  GracefulDisconnect ::= SEQUENCE {
050     *      timeOffline INTEGER (0..720) DEFAULT 0,
051     *      delay [0] INTEGER (0..86400) DEFAULT 0,
052     *      replicatedContexts Referral OPTIONAL
053     * }
054     *  
055     *  Referral ::= SEQUENCE OF LDAPURL
056     *  
057     *  LDAPURL ::= LDAPString -- limited to characters permitted in URLs
058     *  
059     *  LDAPString ::= OCTET STRING
060     * </pre>
061     * 
062     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
063     * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 
064     */
065    public class GracefulDisconnectGrammar extends AbstractGrammar
066    {
067        /** The logger */
068        static final Logger log = LoggerFactory.getLogger( GracefulDisconnectGrammar.class );
069    
070        /** Speedup for logs */
071        static final boolean IS_DEBUG = log.isDebugEnabled();
072    
073        /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */
074        private static IGrammar instance = new GracefulDisconnectGrammar();
075    
076    
077        /**
078         * The action used to store a Time Offline.
079         */
080        GrammarAction storeDelay = new GrammarAction( "Set Graceful Disconnect Delay" )
081        {
082            public void action( IAsn1Container container ) throws DecoderException
083            {
084                GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
085                Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
086        
087                try
088                {
089                    int delay = IntegerDecoder.parse( value, 0, 86400 );
090        
091                    if ( IS_DEBUG )
092                    {
093                        log.debug( "Delay = " + delay );
094                    }
095        
096                    gracefulDisconnectContainer.getGracefulDisconnect().setDelay( delay );
097                    gracefulDisconnectContainer.grammarEndAllowed( true );
098                }
099                catch ( IntegerDecoderException e )
100                {
101                    String msg = I18n.err( I18n.ERR_04036, StringTools.dumpBytes( value.getData() ) );
102                    log.error( msg );
103                    throw new DecoderException( msg );
104                }
105            }
106        };
107        
108        /**
109         * The action used to store a referral.
110         */
111        GrammarAction storeReferral = new GrammarAction( "Stores a referral" )
112        {
113            public void action( IAsn1Container container ) throws DecoderException
114            {
115                GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
116                Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
117    
118                try
119                {
120                    LdapURL url = new LdapURL( value.getData() );
121                    gracefulDisconnectContainer.getGracefulDisconnect().addReplicatedContexts( url );
122                    gracefulDisconnectContainer.grammarEndAllowed( true );
123                    
124                    if ( IS_DEBUG )
125                    {
126                        log.debug( "Stores a referral : {}", url );
127                    }
128                }
129                catch ( LdapURLEncodingException e )
130                {
131                    String msg = "failed to decode the URL '" + StringTools.dumpBytes( value.getData() ) + "'";
132                    log.error( msg );
133                    throw new DecoderException( msg );
134                }
135            }
136        };
137        
138        /**
139         * The action used to store a Time Offline.
140         */
141        GrammarAction storeTimeOffline = new GrammarAction( "Set Graceful Disconnect time offline" )
142        {
143            public void action( IAsn1Container container ) throws DecoderException
144            {
145                GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
146                Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
147    
148                try
149                {
150                    int timeOffline = IntegerDecoder.parse( value, 0, 720 );
151    
152                    if ( IS_DEBUG )
153                    {
154                        log.debug( "Time Offline = " + timeOffline );
155                    }
156    
157                    gracefulDisconnectContainer.getGracefulDisconnect().setTimeOffline( timeOffline );
158                    gracefulDisconnectContainer.grammarEndAllowed( true );
159                }
160                catch ( IntegerDecoderException e )
161                {
162                    String msg = I18n.err( I18n.ERR_04037, StringTools.dumpBytes( value.getData() ) );
163                    log.error( msg );
164                    throw new DecoderException( msg );
165                }
166            }
167        };
168    
169        /**
170         * Creates a new GracefulDisconnectGrammar object.
171         */
172        private GracefulDisconnectGrammar()
173        {
174            name = GracefulDisconnectGrammar.class.getName();
175            statesEnum = GracefulDisconnectStatesEnum.getInstance();
176    
177            // Create the transitions table
178            super.transitions = new GrammarTransition[GracefulDisconnectStatesEnum.LAST_GRACEFUL_DISCONNECT_STATE][256];
179    
180            /**
181             * Transition from init state to graceful disconnect
182             * GracefulDisconnect ::= SEQUENCE { 
183             *     ... 
184             * 
185             * Creates the GracefulDisconnect object
186             */
187            super.transitions[IStates.INIT_GRAMMAR_STATE][UniversalTag.SEQUENCE_TAG] = 
188                new GrammarTransition( IStates.INIT_GRAMMAR_STATE,
189                                        GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE, 
190                                        UniversalTag.SEQUENCE_TAG,
191                    new GrammarAction(
192                    "Init Graceful Disconnect" )
193                {
194                    public void action( IAsn1Container container )
195                    {
196                        GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
197                        GracefulDisconnect gracefulDisconnect = new GracefulDisconnect();
198                        gracefulDisconnectContainer.setGracefulDisconnect( gracefulDisconnect );
199                        gracefulDisconnectContainer.grammarEndAllowed( true );
200                    }
201                } );
202    
203            /**
204             * Transition from graceful disconnect to time offline
205             * 
206             * GracefulDisconnect ::= SEQUENCE { 
207             *     timeOffline INTEGER (0..720) DEFAULT 0, 
208             *     ... 
209             *     
210             * Set the time offline value into the GracefulDisconnect object.    
211             */
212            super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE][UniversalTag.INTEGER_TAG] = 
213                new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
214                                        GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 
215                                        UniversalTag.INTEGER_TAG, 
216                    storeTimeOffline );
217            
218            /**
219             * Transition from graceful disconnect to delay
220             * 
221             * GracefulDisconnect ::= SEQUENCE { 
222             *     ... 
223             *     delay [0] INTEGER (0..86400) DEFAULT 0,
224             *     ... 
225             *     
226             * Set the delay value into the GracefulDisconnect object.    
227             */
228            super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE]
229                             [GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
230                new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
231                                        GracefulDisconnectStatesEnum.DELAY_STATE, 
232                                        GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 
233                    storeDelay );
234            
235            /**
236             * Transition from graceful disconnect to replicated Contexts
237             * 
238             * GracefulDisconnect ::= SEQUENCE { 
239             *     ... 
240             *     replicatedContexts Referral OPTIONAL } 
241             *     
242             * Referral ::= SEQUENCE OF LDAPURL
243             *     
244             * Get some replicated contexts. Nothing to do    
245             */
246            super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE][UniversalTag.SEQUENCE_TAG] = 
247                new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
248                                        GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
249                                        UniversalTag.SEQUENCE_TAG, null );
250            
251            /**
252             * Transition from time offline to delay
253             * 
254             * GracefulDisconnect ::= SEQUENCE { 
255             *     ... 
256             *     delay [0] INTEGER (0..86400) DEFAULT 0,
257             *     ... 
258             *     
259             * Set the delay value into the GracefulDisconnect object.    
260             */
261            super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
262                new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
263                                        GracefulDisconnectStatesEnum.DELAY_STATE, 
264                                        GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
265                    storeDelay );
266    
267            /**
268             * Transition from time offline to replicated Contexts
269             * 
270             * GracefulDisconnect ::= SEQUENCE { 
271             *     ... 
272             *     replicatedContexts Referral OPTIONAL } 
273             *     
274             * Referral ::= SEQUENCE OF LDAPURL
275             *     
276             * Get some replicated contexts. Nothing to do    
277             */
278            super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE][UniversalTag.SEQUENCE_TAG] = 
279                new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
280                                        GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
281                                        UniversalTag.SEQUENCE_TAG, null );
282            
283            /**
284             * Transition from delay to replicated contexts
285             * 
286             * GracefulDisconnect ::= SEQUENCE { 
287             *     ... 
288             *     replicatedContexts Referral OPTIONAL } 
289             *     
290             * Referral ::= SEQUENCE OF LDAPURL
291             *     
292             * Get some replicated contexts. Nothing to do    
293             */
294            super.transitions[GracefulDisconnectStatesEnum.DELAY_STATE][UniversalTag.SEQUENCE_TAG] = 
295                new GrammarTransition( GracefulDisconnectStatesEnum.DELAY_STATE,
296                                        GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 
297                                        UniversalTag.SEQUENCE_TAG, null );
298            
299            /**
300             * Transition from replicated contexts to referral
301             * 
302             * GracefulDisconnect ::= SEQUENCE { 
303             *     ... 
304             *     replicatedContexts Referral OPTIONAL } 
305             *     
306             * Referral ::= SEQUENCE OF LDAPURL
307             *     
308             * Stores the referral
309             */
310            super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE][UniversalTag.OCTET_STRING_TAG] = 
311                new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
312                                        GracefulDisconnectStatesEnum.REFERRAL_STATE, 
313                                        UniversalTag.OCTET_STRING_TAG,
314                    storeReferral );
315    
316            /**
317             * Transition from referral to referral
318             * 
319             * GracefulDisconnect ::= SEQUENCE { 
320             *     ... 
321             *     replicatedContexts Referral OPTIONAL } 
322             *     
323             * Referral ::= SEQUENCE OF LDAPURL
324             *     
325             * Stores the referral
326             */
327            super.transitions[GracefulDisconnectStatesEnum.REFERRAL_STATE][UniversalTag.OCTET_STRING_TAG] = 
328                new GrammarTransition( GracefulDisconnectStatesEnum.REFERRAL_STATE,
329                                        GracefulDisconnectStatesEnum.REFERRAL_STATE, 
330                                        UniversalTag.OCTET_STRING_TAG,
331                    storeReferral );
332    
333        }
334    
335    
336        /**
337         * This class is a singleton.
338         * 
339         * @return An instance on this grammar
340         */
341        public static IGrammar getInstance()
342        {
343            return instance;
344        }
345    }