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 068 * @param decoratedMessage 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 public byte[] getResponseValue() 086 { 087 if ( responseValue == null ) 088 { 089 try 090 { 091 responseValue = encodeInternal().array(); 092 } 093 catch ( EncoderException e ) 094 { 095 LOG.error( I18n.err( I18n.ERR_04164 ), e ); 096 throw new RuntimeException( e ); 097 } 098 } 099 100 return responseValue; 101 } 102 103 104 /** 105 * Sets the response OID specific encoded response values. 106 * 107 * @param responseValue the response specific encoded response values. 108 */ 109 public void setResponseValue( byte[] responseValue ) 110 { 111 GracefulDisconnectDecoder decoder = new GracefulDisconnectDecoder(); 112 113 try 114 { 115 if ( responseValue != null ) 116 { 117 decoder.decode( responseValue ); 118 this.responseValue = new byte[responseValue.length]; 119 System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length ); 120 } 121 else 122 { 123 this.responseValue = null; 124 } 125 } 126 catch ( DecoderException e ) 127 { 128 LOG.error( I18n.err( I18n.ERR_04172 ), e ); 129 } 130 } 131 132 133 /** 134 * {@inheritDoc} 135 */ 136 public int getDelay() 137 { 138 return gracefulDisconnectResponse.getDelay(); 139 } 140 141 142 /** 143 * {@inheritDoc} 144 */ 145 public void setDelay( int delay ) 146 { 147 gracefulDisconnectResponse.setDelay( delay ); 148 } 149 150 151 /** 152 * {@inheritDoc} 153 */ 154 public int getTimeOffline() 155 { 156 return gracefulDisconnectResponse.getTimeOffline(); 157 } 158 159 160 /** 161 * {@inheritDoc} 162 */ 163 public void setTimeOffline( int timeOffline ) 164 { 165 gracefulDisconnectResponse.setTimeOffline( timeOffline ); 166 } 167 168 169 /** 170 * {@inheritDoc} 171 */ 172 public Referral getReplicatedContexts() 173 { 174 return gracefulDisconnectResponse.getReplicatedContexts(); 175 } 176 177 178 /** 179 * {@inheritDoc} 180 */ 181 public void addReplicatedContexts( String replicatedContext ) 182 { 183 gracefulDisconnectResponse.getReplicatedContexts().addLdapUrl( replicatedContext ); 184 } 185 186 187 /** 188 * Compute the GracefulDisconnect length 189 * <pre> 190 * 0x30 L1 191 * | 192 * +--> [ 0x02 0x0(1-4) [0..720] ] 193 * +--> [ 0x80 0x0(1-3) [0..86400] ] 194 * +--> [ 0x30 L2 195 * | 196 * +--> (0x04 L3 value) + ] 197 * </pre> 198 */ 199 /* no qualifier */ int computeLengthInternal() 200 { 201 gracefulDisconnectSequenceLength = 0; 202 203 if ( gracefulDisconnectResponse.getTimeOffline() != 0 ) 204 { 205 gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getTimeOffline() ); 206 } 207 208 if ( gracefulDisconnectResponse.getDelay() != 0 ) 209 { 210 gracefulDisconnectSequenceLength += 1 + 1 + BerValue.getNbBytes( gracefulDisconnectResponse.getDelay() ); 211 } 212 213 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) && 214 ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) ) 215 { 216 replicatedContextsLength = 0; 217 218 ldapUrlBytes = new ArrayList<byte[]>( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() ); 219 220 // We may have more than one reference. 221 for ( String replicatedContext : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() ) 222 { 223 byte[] bytes = Strings.getBytesUtf8( replicatedContext ); 224 ldapUrlBytes.add( bytes ); 225 int ldapUrlLength = bytes.length; 226 replicatedContextsLength += 1 + TLV.getNbBytes( ldapUrlLength ) + ldapUrlLength; 227 } 228 229 gracefulDisconnectSequenceLength += 1 + TLV.getNbBytes( replicatedContextsLength ) 230 + replicatedContextsLength; 231 } 232 233 return 1 + TLV.getNbBytes( gracefulDisconnectSequenceLength ) + gracefulDisconnectSequenceLength; 234 } 235 236 237 /** 238 * Encodes the gracefulDisconnect extended operation. 239 * 240 * @return A ByteBuffer that contains the encoded PDU 241 * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong. 242 */ 243 /* no qualifier */ ByteBuffer encodeInternal() throws EncoderException 244 { 245 // Allocate the bytes buffer. 246 ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() ); 247 248 249 bb.put( UniversalTag.SEQUENCE.getValue() ); 250 bb.put( TLV.getBytes( gracefulDisconnectSequenceLength ) ); 251 252 if ( gracefulDisconnectResponse.getTimeOffline() != 0 ) 253 { 254 BerValue.encode( bb, gracefulDisconnectResponse.getTimeOffline() ); 255 } 256 257 if ( gracefulDisconnectResponse.getDelay() != 0 ) 258 { 259 bb.put( ( byte ) GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG ); 260 bb.put( ( byte ) TLV.getNbBytes( gracefulDisconnectResponse.getDelay() ) ); 261 bb.put( BerValue.getBytes( gracefulDisconnectResponse.getDelay() ) ); 262 } 263 264 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) && 265 ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) ) 266 { 267 bb.put( UniversalTag.SEQUENCE.getValue() ); 268 bb.put( TLV.getBytes( replicatedContextsLength ) ); 269 270 // We may have more than one reference. 271 for ( byte[] replicatedContext : ldapUrlBytes ) 272 { 273 BerValue.encode( bb, replicatedContext ); 274 } 275 } 276 277 return bb; 278 } 279 280 281 /** 282 * Return a string representation of the graceful disconnect 283 */ 284 public String toString() 285 { 286 StringBuffer sb = new StringBuffer(); 287 288 sb.append( "Graceful Disconnect extended operation" ); 289 sb.append( " TimeOffline : " ).append( gracefulDisconnectResponse.getTimeOffline() ).append( '\n' ); 290 sb.append( " Delay : " ).append( gracefulDisconnectResponse.getDelay() ).append( '\n' ); 291 292 if ( ( gracefulDisconnectResponse.getReplicatedContexts() != null ) && ( gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls().size() != 0 ) ) 293 { 294 sb.append( " Replicated contexts :" ); 295 296 // We may have more than one reference. 297 for ( String url : gracefulDisconnectResponse.getReplicatedContexts().getLdapUrls() ) 298 { 299 sb.append( "\n " ).append( url ); 300 } 301 } 302 303 return sb.toString(); 304 } 305}