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