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.model.exception.LdapURLEncodingException; 033import org.apache.directory.api.ldap.model.url.LdapUrl; 034import org.apache.directory.api.util.Strings; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038 039/** 040 * This class implements the Graceful Disconnect. All the actions are declared 041 * in this class. As it is a singleton, these declaration are only done once. 042 * The grammar is : 043 * 044 * <pre> 045 * GracefulDisconnect ::= SEQUENCE { 046 * timeOffline INTEGER (0..720) DEFAULT 0, 047 * delay [0] INTEGER (0..86400) DEFAULT 0, 048 * replicatedContexts Referral OPTIONAL 049 * } 050 * 051 * Referral ::= SEQUENCE OF LDAPURL 052 * 053 * LDAPURL ::= LDAPString -- limited to characters permitted in URLs 054 * 055 * LDAPString ::= OCTET STRING 056 * </pre> 057 * 058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 059 */ 060public final class GracefulDisconnectResponseGrammar extends AbstractGrammar<GracefulDisconnectResponseContainer> 061{ 062 /** The logger */ 063 static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectResponseGrammar.class ); 064 065 /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */ 066 private static GracefulDisconnectResponseGrammar instance = new GracefulDisconnectResponseGrammar(); 067 068 /** 069 * The action used to store a Time Offline. 070 */ 071 private GrammarAction<GracefulDisconnectResponseContainer> storeDelay = 072 new GrammarAction<GracefulDisconnectResponseContainer>( "Set Graceful Disconnect Delay" ) 073 { 074 public void action( GracefulDisconnectResponseContainer container ) throws DecoderException 075 { 076 BerValue value = container.getCurrentTLV().getValue(); 077 078 try 079 { 080 int delay = IntegerDecoder.parse( value, 0, 86400 ); 081 082 if ( LOG.isDebugEnabled() ) 083 { 084 LOG.debug( I18n.msg( I18n.MSG_08204_DELAY, delay ) ); 085 } 086 087 container.getGracefulDisconnectResponse().setDelay( delay ); 088 container.setGrammarEndAllowed( true ); 089 } 090 catch ( IntegerDecoderException ide ) 091 { 092 String msg = I18n.err( I18n.ERR_08205_CANNOT_DECODE_DELAY, Strings.dumpBytes( value.getData() ) ); 093 LOG.error( msg ); 094 throw new DecoderException( msg, ide ); 095 } 096 } 097 }; 098 099 /** 100 * The action used to store a referral. 101 */ 102 private GrammarAction<GracefulDisconnectResponseContainer> storeReferral = 103 new GrammarAction<GracefulDisconnectResponseContainer>( "Stores a referral" ) 104 { 105 public void action( GracefulDisconnectResponseContainer container ) throws DecoderException 106 { 107 BerValue value = container.getCurrentTLV().getValue(); 108 109 try 110 { 111 if ( Strings.isEmpty( value.getData() ) ) 112 { 113 String msg = I18n.err( I18n.ERR_08224_NULL_URL_DECODING_FAILURE ); 114 LOG.error( msg ); 115 throw new DecoderException( msg ); 116 } 117 118 String url = Strings.utf8ToString( value.getData() ); 119 120 LdapUrl ldapUrl = new LdapUrl( url ); 121 container.getGracefulDisconnectResponse().addReplicatedContexts( url ); 122 container.setGrammarEndAllowed( true ); 123 124 if ( LOG.isDebugEnabled() ) 125 { 126 LOG.debug( I18n.msg( I18n.MSG_08214_STORES_A_REFERRAL, ldapUrl ) ); 127 } 128 } 129 catch ( LdapURLEncodingException luee ) 130 { 131 String msg = I18n.err( I18n.ERR_08225_URL_DECODING_FAILURE, Strings.dumpBytes( value.getData() ) ); 132 LOG.error( msg ); 133 throw new DecoderException( msg, luee ); 134 } 135 } 136 }; 137 138 /** 139 * The action used to store a Time Offline. 140 */ 141 private GrammarAction<GracefulDisconnectResponseContainer> storeTimeOffline = 142 new GrammarAction<GracefulDisconnectResponseContainer>( "Set Graceful Disconnect time offline" ) 143 { 144 public void action( GracefulDisconnectResponseContainer container ) throws DecoderException 145 { 146 BerValue value = container.getCurrentTLV().getValue(); 147 148 try 149 { 150 int timeOffline = IntegerDecoder.parse( value, 0, 720 ); 151 152 if ( LOG.isDebugEnabled() ) 153 { 154 LOG.debug( I18n.msg( I18n.MSG_08216_TIME_OFFLINE, timeOffline ) ); 155 } 156 157 container.getGracefulDisconnectResponse().setTimeOffline( timeOffline ); 158 container.setGrammarEndAllowed( true ); 159 } 160 catch ( IntegerDecoderException ide ) 161 { 162 String msg = I18n.err( I18n.ERR_08206_TIME_OFFLINE_DECODING_FAILED, Strings.dumpBytes( value.getData() ) ); 163 LOG.error( msg ); 164 throw new DecoderException( msg, ide ); 165 } 166 } 167 }; 168 169 170 /** 171 * Creates a new GracefulDisconnectGrammar object. 172 */ 173 @SuppressWarnings("unchecked") 174 private GracefulDisconnectResponseGrammar() 175 { 176 setName( GracefulDisconnectResponseGrammar.class.getName() ); 177 178 // Create the transitions table 179 super.transitions = new GrammarTransition[GracefulDisconnectStatesEnum.LAST_GRACEFUL_DISCONNECT_STATE.ordinal()][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[GracefulDisconnectStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 189 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.START_STATE, 190 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE, 191 UniversalTag.SEQUENCE.getValue(), 192 new GrammarAction<GracefulDisconnectResponseContainer>( "Init Graceful Disconnect" ) 193 { 194 public void action( GracefulDisconnectResponseContainer container ) 195 { 196 if ( container.getCurrentTLV().getLength() == 0 ) 197 { 198 container.setGrammarEndAllowed( true ); 199 } 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.ordinal()][UniversalTag.INTEGER 213 .getValue()] = 214 new GrammarTransition<GracefulDisconnectResponseContainer>( 215 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE, 216 GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 217 UniversalTag.INTEGER.getValue(), 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.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 230 new GrammarTransition<GracefulDisconnectResponseContainer>( 231 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.ordinal()][UniversalTag.SEQUENCE 248 .getValue()] = 249 new GrammarTransition<GracefulDisconnectResponseContainer>( 250 GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE, 251 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 252 UniversalTag.SEQUENCE.getValue(), null ); 253 254 /** 255 * Transition from time offline to delay 256 * 257 * GracefulDisconnect ::= SEQUENCE { 258 * ... 259 * delay [0] INTEGER (0..86400) DEFAULT 0, 260 * ... 261 * 262 * Set the delay value into the GracefulDisconnect object. 263 */ 264 super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 265 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 266 GracefulDisconnectStatesEnum.DELAY_STATE, 267 GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 268 storeDelay ); 269 270 /** 271 * Transition from time offline to replicated Contexts 272 * 273 * GracefulDisconnect ::= SEQUENCE { 274 * ... 275 * replicatedContexts Referral OPTIONAL } 276 * 277 * Referral ::= SEQUENCE OF LDAPURL 278 * 279 * Get some replicated contexts. Nothing to do 280 */ 281 super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 282 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 283 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 284 UniversalTag.SEQUENCE.getValue(), null ); 285 286 /** 287 * Transition from delay to replicated contexts 288 * 289 * GracefulDisconnect ::= SEQUENCE { 290 * ... 291 * replicatedContexts Referral OPTIONAL } 292 * 293 * Referral ::= SEQUENCE OF LDAPURL 294 * 295 * Get some replicated contexts. Nothing to do 296 */ 297 super.transitions[GracefulDisconnectStatesEnum.DELAY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 298 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.DELAY_STATE, 299 GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 300 UniversalTag.SEQUENCE.getValue(), null ); 301 302 /** 303 * Transition from replicated contexts to referral 304 * 305 * GracefulDisconnect ::= SEQUENCE { 306 * ... 307 * replicatedContexts Referral OPTIONAL } 308 * 309 * Referral ::= SEQUENCE OF LDAPURL 310 * 311 * Stores the referral 312 */ 313 super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE.ordinal()][UniversalTag.OCTET_STRING 314 .getValue()] = 315 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 316 GracefulDisconnectStatesEnum.REFERRAL_STATE, 317 UniversalTag.OCTET_STRING.getValue(), 318 storeReferral ); 319 320 /** 321 * Transition from referral to referral 322 * 323 * GracefulDisconnect ::= SEQUENCE { 324 * ... 325 * replicatedContexts Referral OPTIONAL } 326 * 327 * Referral ::= SEQUENCE OF LDAPURL 328 * 329 * Stores the referral 330 */ 331 super.transitions[GracefulDisconnectStatesEnum.REFERRAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 332 new GrammarTransition<GracefulDisconnectResponseContainer>( GracefulDisconnectStatesEnum.REFERRAL_STATE, 333 GracefulDisconnectStatesEnum.REFERRAL_STATE, 334 UniversalTag.OCTET_STRING.getValue(), 335 storeReferral ); 336 337 } 338 339 340 /** 341 * This class is a singleton. 342 * 343 * @return An instance on this grammar 344 */ 345 public static GracefulDisconnectResponseGrammar getInstance() 346 { 347 return instance; 348 } 349}