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 java.nio.ByteBuffer; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.directory.api.asn1.DecoderException; 028import org.apache.directory.api.asn1.EncoderException; 029import org.apache.directory.api.asn1.ber.tlv.BerValue; 030import org.apache.directory.api.asn1.ber.tlv.TLV; 031import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 032import org.apache.directory.api.i18n.I18n; 033import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator; 034import org.apache.directory.api.ldap.codec.api.LdapApiService; 035import org.apache.directory.api.ldap.extras.extended.gracefulDisconnect.GracefulDisconnectResponse; 036import org.apache.directory.api.ldap.model.message.Referral; 037import org.apache.directory.api.util.Strings; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041 042/** 043 * A Decorator for CancelResponses. 044 * 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 */ 047public class GracefulDisconnectResponseDecorator extends ExtendedResponseDecorator<GracefulDisconnectResponse> 048 implements GracefulDisconnectResponse 049{ 050 /** The logger. */ 051 private static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectResponseDecorator.class ); 052 053 /** Length of the sequence */ 054 private int gracefulDisconnectSequenceLength; 055 056 /** Length of the replicated contexts */ 057 private int replicatedContextsLength; 058 059 /** The encoded LDAP URL list */ 060 private List<byte[]> ldapUrlBytes; 061 062 private GracefulDisconnectResponse gracefulDisconnectResponse; 063 064 /** 065 * Creates a new instance of CancelResponseDecorator. 066 * 067 * @param codec The LDAP service instance 068 * @param decoratedMessage The decorated message 069 */ 070 public GracefulDisconnectResponseDecorator( LdapApiService codec, GracefulDisconnectResponse decoratedMessage ) 071 { 072 super( codec, decoratedMessage ); 073 gracefulDisconnectResponse = decoratedMessage; 074 } 075 076 077 // ------------------------------------------------------------------------ 078 // ExtendedResponse Interface Method Implementations 079 // ------------------------------------------------------------------------ 080 /** 081 * Gets the response OID specific encoded response values. 082 * 083 * @return the response specific encoded response values. 084 */ 085 @Override 086 public byte[] getResponseValue() 087 { 088 if ( responseValue == null ) 089 { 090 try 091 { 092 responseValue = encodeInternal().array(); 093 } 094 catch ( EncoderException e ) 095 { 096 LOG.error( I18n.err( I18n.ERR_04164 ), e ); 097 throw new RuntimeException( e ); 098 } 099 } 100 101 return responseValue; 102 } 103 104 105 /** 106 * Sets the response OID specific encoded response values. 107 * 108 * @param responseValue the response specific encoded response values. 109 */ 110 @Override 111 public void setResponseValue( byte[] responseValue ) 112 { 113 GracefulDisconnectDecoder decoder = new GracefulDisconnectDecoder(); 114 115 try 116 { 117 if ( responseValue != null ) 118 { 119 decoder.decode( responseValue ); 120 this.responseValue = new byte[responseValue.length]; 121 System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length ); 122 } 123 else 124 { 125 this.responseValue = null; 126 } 127 } 128 catch ( DecoderException e ) 129 { 130 LOG.error( I18n.err( I18n.ERR_04172 ), e ); 131 } 132 } 133 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public int getDelay() 140 { 141 return gracefulDisconnectResponse.getDelay(); 142 } 143 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public void setDelay( int delay ) 150 { 151 gracefulDisconnectResponse.setDelay( delay ); 152 } 153 154 155 /** 156 * {@inheritDoc} 157 */ 158 @Override 159 public int getTimeOffline() 160 { 161 return gracefulDisconnectResponse.getTimeOffline(); 162 } 163 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public void setTimeOffline( int timeOffline ) 170 { 171 gracefulDisconnectResponse.setTimeOffline( timeOffline ); 172 } 173 174 175 /** 176 * {@inheritDoc} 177 */ 178 @Override 179 public Referral getReplicatedContexts() 180 { 181 return gracefulDisconnectResponse.getReplicatedContexts(); 182 } 183 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public void addReplicatedContexts( String replicatedContext ) 190 { 191 gracefulDisconnectResponse.getReplicatedContexts().addLdapUrl( replicatedContext ); 192 } 193 194 195 /** 196 * Compute the GracefulDisconnect length 197 * <pre> 198 * 0x30 L1 199 * | 200 * +--> [ 0x02 0x0(1-4) [0..720] ] 201 * +--> [ 0x80 0x0(1-3) [0..86400] ] 202 * +--> [ 0x30 L2 203 * | 204 * +--> (0x04 L3 value) + ] 205 * </pre> 206 */ 207 /* no qualifier */ int computeLengthInternal() 208 { 209 gracefulDisconnectSequenceLength = 0; 210 211 if ( gracefulDisconnectResponse.getTimeOffline() != 0 ) 212 { 213 gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getTimeOffline() ); 214 } 215 216 if ( gracefulDisconnectResponse.getDelay() != 0 ) 217 { 218 gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getDelay() ); 219 } 220 221 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) 222 && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) ) 223 { 224 replicatedContextsLength = 0; 225 226 ldapUrlBytes = new ArrayList<>( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() ); 227 228 // We may have more than one reference. 229 for ( String replicatedContext : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() ) 230 { 231 byte[] bytes = Strings.getBytesUtf8( replicatedContext ); 232 ldapUrlBytes.add( bytes ); 233 int ldapUrlLength = bytes.length; 234 replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength; 235 } 236 237 gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength ) 238 + replicatedContextsLength; 239 } 240 241 return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength; 242 } 243 244 245 /** 246 * Encodes the gracefulDisconnect extended operation. 247 * 248 * @return A ByteBuffer that contains the encoded PDU 249 * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong. 250 */ 251 /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException 252 { 253 // Allocate the bytes buffer. 254 ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() ); 255 256 257 bb.put( UniversalTag.SEQUENCE.getValue() ); 258 bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) ); 259 260 if ( gracefulDisconnectResponse.getTimeOffline() != 0 ) 261 { 262 BerValue.encode( bb, gracefulDisconnectResponse.getTimeOffline() ); 263 } 264 265 if ( gracefulDisconnectResponse.getDelay() != 0 ) 266 { 267 bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG ); 268 bb.put( ( byte ) TLV.getNbBytes( gracefulDisconnectResponse.getDelay() ) ); 269 bb.put( BerValue.getBytes( gracefulDisconnectResponse.getDelay() ) ); 270 } 271 272 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) 273 && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) ) 274 { 275 bb.put( UniversalTag.SEQUENCE.getValue() ); 276 bb.put( TLV.getBytes( replicatedContextsLength ) ); 277 278 // We may have more than one reference. 279 for ( byte[] replicatedContext : ldapUrlBytes ) 280 { 281 BerValue.encode( bb, replicatedContext ); 282 } 283 } 284 285 return bb; 286 } 287 288 289 /** 290 * Return a string representation of the graceful disconnect 291 */ 292 @Override 293 public String toString() 294 { 295 StringBuilder sb = new StringBuilder(); 296 297 sb.append( "Graceful Disconnect extended operation" ); 298 sb.append( " TimeOffline : " ).append( gracefulDisconnectResponse.getTimeOffline() ).append( '\n' ); 299 sb.append( " Delay : " ).append( gracefulDisconnectResponse.getDelay() ).append( '\n' ); 300 301 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) 302 && ( !gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().isEmpty() ) ) 303 { 304 sb.append( " Replicated contexts :" ); 305 306 // We may have more than one reference. 307 for ( String url : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() ) 308 { 309 sb.append( "\n " ).append( url ); 310 } 311 } 312 313 return sb.toString(); 314 } 315}