View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.api.ldap.extras.extended.ads_impl.gracefulDisconnect;
21  
22  
23  import org.apache.directory.api.asn1.DecoderException;
24  import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
25  import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
26  import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
27  import org.apache.directory.api.asn1.ber.tlv.BerValue;
28  import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
29  import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
30  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
31  import org.apache.directory.api.i18n.I18n;
32  import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
33  import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponseImpl;
34  import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException;
35  import org.apache.directory.api.ldap.model.url.LdapUrl;
36  import org.apache.directory.api.util.Strings;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * This class implements the Graceful Disconnect. All the actions are declared
43   * in this class. As it is a singleton, these declaration are only done once.
44   * The grammar is :
45   * 
46   * <pre>
47   *  GracefulDisconnect ::= SEQUENCE {
48   *      timeOffline INTEGER (0..720) DEFAULT 0,
49   *      delay [0] INTEGER (0..86400) DEFAULT 0,
50   *      replicatedContexts Referral OPTIONAL
51   * }
52   *  
53   *  Referral ::= SEQUENCE OF LDAPURL
54   *  
55   *  LDAPURL ::= LDAPString -- limited to characters permitted in URLs
56   *  
57   *  LDAPString ::= OCTET STRING
58   * </pre>
59   * 
60   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
61   */
62  public final class GracefulDisconnectGrammar extends AbstractGrammar<GracefulDisconnectContainer>
63  {
64      /** The logger */
65      static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectGrammar.class );
66  
67      /** Speedup for logs */
68      static final boolean IS_DEBUG = LOG.isDebugEnabled();
69  
70      /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */
71      private static GracefulDisconnectGrammar instance = new GracefulDisconnectGrammar();
72  
73      /**
74       * The action used to store a Time Offline.
75       */
76      private GrammarAction<GracefulDisconnectContainer> storeDelay =
77          new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect Delay" )
78          {
79              public void action( GracefulDisconnectContainer container ) throws DecoderException
80              {
81                  BerValue value = container.getCurrentTLV().getValue();
82  
83                  try
84                  {
85                      int delay = IntegerDecoder.parse( value, 0, 86400 );
86  
87                      if ( IS_DEBUG )
88                      {
89                          LOG.debug( "Delay = " + delay );
90                      }
91  
92                      container.getGracefulDisconnectResponse().setDelay( delay );
93                      container.setGrammarEndAllowed( true );
94                  }
95                  catch ( IntegerDecoderException e )
96                  {
97                      String msg = I18n.err( I18n.ERR_04036, Strings.dumpBytes( value.getData() ) );
98                      LOG.error( msg );
99                      throw new DecoderException( msg );
100                 }
101             }
102         };
103 
104     /**
105      * The action used to store a referral.
106      */
107     private GrammarAction<GracefulDisconnectContainer> storeReferral =
108         new GrammarAction<GracefulDisconnectContainer>( "Stores a referral" )
109         {
110             public void action( GracefulDisconnectContainer container ) throws DecoderException
111             {
112                 BerValue value = container.getCurrentTLV().getValue();
113 
114                 try
115                 {
116                     if ( Strings.isEmpty( value.getData() ) )
117                     {
118                         String msg = "failed to decode a null URL";
119                         LOG.error( msg );
120                         throw new DecoderException( msg );
121                     }
122 
123                     String url = Strings.utf8ToString( value.getData() );
124 
125                     LdapUrl ldapUrl = new LdapUrl( url );
126                     container.getGracefulDisconnectResponse().addReplicatedContexts( url );
127                     container.setGrammarEndAllowed( true );
128 
129                     if ( IS_DEBUG )
130                     {
131                         LOG.debug( "Stores a referral : {}", ldapUrl );
132                     }
133                 }
134                 catch ( LdapURLEncodingException e )
135                 {
136                     String msg = "failed to decode the URL '" + Strings.dumpBytes( value.getData() ) + "'";
137                     LOG.error( msg );
138                     throw new DecoderException( msg );
139                 }
140             }
141         };
142 
143     /**
144      * The action used to store a Time Offline.
145      */
146     private GrammarAction<GracefulDisconnectContainer> storeTimeOffline =
147         new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect time offline" )
148         {
149             public void action( GracefulDisconnectContainer container ) throws DecoderException
150             {
151                 BerValue value = container.getCurrentTLV().getValue();
152 
153                 try
154                 {
155                     int timeOffline = IntegerDecoder.parse( value, 0, 720 );
156 
157                     if ( IS_DEBUG )
158                     {
159                         LOG.debug( "Time Offline = " + timeOffline );
160                     }
161 
162                     container.getGracefulDisconnectResponse().setTimeOffline( timeOffline );
163                     container.setGrammarEndAllowed( true );
164                 }
165                 catch ( IntegerDecoderException e )
166                 {
167                     String msg = I18n.err( I18n.ERR_04037, Strings.dumpBytes( value.getData() ) );
168                     LOG.error( msg );
169                     throw new DecoderException( msg );
170                 }
171             }
172         };
173 
174 
175     /**
176      * Creates a new GracefulDisconnectGrammar object.
177      */
178     @SuppressWarnings("unchecked")
179     private GracefulDisconnectGrammar()
180     {
181         setName( GracefulDisconnectGrammar.class.getName() );
182 
183         // Create the transitions table
184         super.transitions = new GrammarTransition[GracefulDisconnectStatesEnum.LAST_GRACEFUL_DISCONNECT_STATE.ordinal()][256];
185 
186         /**
187          * Transition from init state to graceful disconnect
188          * GracefulDisconnect ::= SEQUENCE { 
189          *     ... 
190          * 
191          * Creates the GracefulDisconnect object
192          */
193         super.transitions[GracefulDisconnectStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
194             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.START_STATE,
195                 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
196                 UniversalTag.SEQUENCE.getValue(),
197                 new GrammarAction<GracefulDisconnectContainer>( "Init Graceful Disconnect" )
198                 {
199                     public void action( GracefulDisconnectContainer container )
200                     {
201                         GracefulDisconnectResponseDecorator gracefulDisconnectResponse = 
202                             new GracefulDisconnectResponseDecorator(
203                                 LdapApiServiceFactory.getSingleton(),
204                                 new GracefulDisconnectResponseImpl()
205                                 );
206                         container.setGracefulDisconnectResponse( gracefulDisconnectResponse );
207                         container.setGrammarEndAllowed( true );
208                     }
209                 } );
210 
211         /**
212          * Transition from graceful disconnect to time offline
213          * 
214          * GracefulDisconnect ::= SEQUENCE { 
215          *     timeOffline INTEGER (0..720) DEFAULT 0, 
216          *     ... 
217          *     
218          * Set the time offline value into the GracefulDisconnect object.    
219          */
220         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER
221             .getValue()] =
222             new GrammarTransition<GracefulDisconnectContainer>(
223                 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
224                 GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
225                 UniversalTag.INTEGER.getValue(), storeTimeOffline );
226 
227         /**
228          * Transition from graceful disconnect to delay
229          * 
230          * GracefulDisconnect ::= SEQUENCE { 
231          *     ... 
232          *     delay [0] INTEGER (0..86400) DEFAULT 0,
233          *     ... 
234          *     
235          * Set the delay value into the GracefulDisconnect object.    
236          */
237         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
238             new GrammarTransition<GracefulDisconnectContainer>(
239                 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
240                 GracefulDisconnectStatesEnum.DELAY_STATE,
241                 GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
242                 storeDelay );
243 
244         /**
245          * Transition from graceful disconnect to replicated Contexts
246          * 
247          * GracefulDisconnect ::= SEQUENCE { 
248          *     ... 
249          *     replicatedContexts Referral OPTIONAL } 
250          *     
251          * Referral ::= SEQUENCE OF LDAPURL
252          *     
253          * Get some replicated contexts. Nothing to do    
254          */
255         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.SEQUENCE
256             .getValue()] =
257             new GrammarTransition<GracefulDisconnectContainer>(
258                 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
259                 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
260                 UniversalTag.SEQUENCE.getValue(), null );
261 
262         /**
263          * Transition from time offline to delay
264          * 
265          * GracefulDisconnect ::= SEQUENCE { 
266          *     ... 
267          *     delay [0] INTEGER (0..86400) DEFAULT 0,
268          *     ... 
269          *     
270          * Set the delay value into the GracefulDisconnect object.    
271          */
272         super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] =
273             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
274                 GracefulDisconnectStatesEnum.DELAY_STATE,
275                 GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
276                 storeDelay );
277 
278         /**
279          * Transition from time offline to replicated Contexts
280          * 
281          * GracefulDisconnect ::= SEQUENCE { 
282          *     ... 
283          *     replicatedContexts Referral OPTIONAL } 
284          *     
285          * Referral ::= SEQUENCE OF LDAPURL
286          *     
287          * Get some replicated contexts. Nothing to do    
288          */
289         super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
290             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
291                 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
292                 UniversalTag.SEQUENCE.getValue(), null );
293 
294         /**
295          * Transition from delay to replicated contexts
296          * 
297          * GracefulDisconnect ::= SEQUENCE { 
298          *     ... 
299          *     replicatedContexts Referral OPTIONAL } 
300          *     
301          * Referral ::= SEQUENCE OF LDAPURL
302          *     
303          * Get some replicated contexts. Nothing to do    
304          */
305         super.transitions[GracefulDisconnectStatesEnum.DELAY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
306             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.DELAY_STATE,
307                 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
308                 UniversalTag.SEQUENCE.getValue(), null );
309 
310         /**
311          * Transition from replicated contexts to referral
312          * 
313          * GracefulDisconnect ::= SEQUENCE { 
314          *     ... 
315          *     replicatedContexts Referral OPTIONAL } 
316          *     
317          * Referral ::= SEQUENCE OF LDAPURL
318          *     
319          * Stores the referral
320          */
321         super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE.ordinal()][UniversalTag.OCTET_STRING
322             .getValue()] =
323             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
324                 GracefulDisconnectStatesEnum.REFERRAL_STATE,
325                 UniversalTag.OCTET_STRING.getValue(),
326                 storeReferral );
327 
328         /**
329          * Transition from referral to referral
330          * 
331          * GracefulDisconnect ::= SEQUENCE { 
332          *     ... 
333          *     replicatedContexts Referral OPTIONAL } 
334          *     
335          * Referral ::= SEQUENCE OF LDAPURL
336          *     
337          * Stores the referral
338          */
339         super.transitions[GracefulDisconnectStatesEnum.REFERRAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
340             new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REFERRAL_STATE,
341                 GracefulDisconnectStatesEnum.REFERRAL_STATE,
342                 UniversalTag.OCTET_STRING.getValue(),
343                 storeReferral );
344 
345     }
346 
347 
348     /**
349      * This class is a singleton.
350      * 
351      * @return An instance on this grammar
352      */
353     public static GracefulDisconnectGrammar getInstance()
354     {
355         return instance;
356     }
357 }