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.api.ldap.extras.extended.ads_impl.gracefulDisconnect; 021 022 023import org.apache.directory.api.asn1.DecoderException; 024import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar; 025import org.apache.directory.api.asn1.ber.grammar.GrammarAction; 026import org.apache.directory.api.asn1.ber.grammar.GrammarTransition; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder; 029import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException; 030import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 031import org.apache.directory.api.i18n.I18n; 032import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory; 033import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponseImpl; 034import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException; 035import org.apache.directory.api.ldap.model.url.LdapUrl; 036import org.apache.directory.api.util.Strings; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040 041/** 042 * This class implements the Graceful Disconnect. All the actions are declared 043 * in this class. As it is a singleton, these declaration are only done once. 044 * The grammar is : 045 * 046 * <pre> 047 * GracefulDisconnect ::= SEQUENCE { 048 * timeOffline INTEGER (0..720) DEFAULT 0, 049 * delay [0] INTEGER (0..86400) DEFAULT 0, 050 * replicatedContexts Referral OPTIONAL 051 * } 052 * 053 * Referral ::= SEQUENCE OF LDAPURL 054 * 055 * LDAPURL ::= LDAPString -- limited to characters permitted in URLs 056 * 057 * LDAPString ::= OCTET STRING 058 * </pre> 059 * 060 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 061 */ 062public final class GracefulDisconnectGrammar extends AbstractGrammar<GracefulDisconnectContainer> 063{ 064 /** The logger */ 065 static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectGrammar.class ); 066 067 /** Speedup for logs */ 068 static final boolean IS_DEBUG = LOG.isDebugEnabled(); 069 070 /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */ 071 private static GracefulDisconnectGrammar instance = new GracefulDisconnectGrammar(); 072 073 /** 074 * The action used to store a Time Offline. 075 */ 076 private GrammarAction<GracefulDisconnectContainer> storeDelay = 077 new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect Delay" ) 078 { 079 public void action( GracefulDisconnectContainer container ) throws DecoderException 080 { 081 BerValue value = container.getCurrentTLV().getValue(); 082 083 try 084 { 085 int delay = IntegerDecoder.parse( value, 0, 86400 ); 086 087 if ( IS_DEBUG ) 088 { 089 LOG.debug( "Delay = " + delay ); 090 } 091 092 container.getGracefulDisconnectResponse().setDelay( delay ); 093 container.setGrammarEndAllowed( true ); 094 } 095 catch ( IntegerDecoderException ide ) 096 { 097 String msg = I18n.err( I18n.ERR_04036, Strings.dumpBytes( value.getData() ) ); 098 LOG.error( msg ); 099 throw new DecoderException( msg, ide ); 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 luee ) 135 { 136 String msg = "failed to decode the URL '" + Strings.dumpBytes( value.getData() ) + "'"; 137 LOG.error( msg ); 138 throw new DecoderException( msg, luee ); 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 ide ) 166 { 167 String msg = I18n.err( I18n.ERR_04037, Strings.dumpBytes( value.getData() ) ); 168 LOG.error( msg ); 169 throw new DecoderException( msg, ide ); 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}