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 }