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; 021 022 023 import java.nio.BufferOverflowException; 024 import java.nio.ByteBuffer; 025 import java.util.ArrayList; 026 import java.util.HashMap; 027 import java.util.List; 028 import java.util.Map; 029 030 import org.apache.directory.shared.asn1.AbstractAsn1Object; 031 import org.apache.directory.shared.asn1.ber.tlv.TLV; 032 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 033 import org.apache.directory.shared.asn1.ber.tlv.Value; 034 import org.apache.directory.shared.asn1.codec.EncoderException; 035 import org.apache.directory.shared.i18n.I18n; 036 import org.apache.directory.shared.ldap.codec.controls.CodecControl; 037 import org.apache.directory.shared.ldap.codec.controls.ManageDsaITControl; 038 import org.apache.directory.shared.ldap.codec.controls.replication.syncDoneValue.SyncDoneValueControl; 039 import org.apache.directory.shared.ldap.codec.controls.replication.syncInfoValue.SyncInfoValueControl; 040 import org.apache.directory.shared.ldap.codec.controls.replication.syncRequestValue.SyncRequestValueControl; 041 import org.apache.directory.shared.ldap.codec.controls.replication.syncStateValue.SyncStateValueControl; 042 import org.apache.directory.shared.ldap.codec.search.controls.pagedSearch.PagedResultsControl; 043 import org.apache.directory.shared.ldap.codec.search.controls.persistentSearch.PersistentSearchControl; 044 import org.apache.directory.shared.ldap.codec.search.controls.subentries.SubentriesControl; 045 import org.apache.directory.shared.ldap.message.control.Control; 046 import org.apache.directory.shared.ldap.message.control.replication.SynchronizationInfoEnum; 047 048 049 /** 050 * The main ldapObject : every Ldap Message are encapsulated in it. It contains 051 * a message Id, a operation (protocolOp) and one ore more Controls. 052 * 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 055 */ 056 public abstract class LdapMessageCodec extends AbstractAsn1Object 057 { 058 // ~ Instance fields 059 // ---------------------------------------------------------------------------- 060 061 /** The message ID */ 062 private int messageId; 063 064 /** The controls */ 065 private List<Control> controls; 066 067 /** The current control */ 068 private Control currentControl; 069 070 /** The LdapMessage length */ 071 protected int ldapMessageLength; 072 073 /** The controls length */ 074 private int controlsLength; 075 076 /** The controls sequence length */ 077 private int controlsSequenceLength; 078 079 private Map<String, Control> codecControls = new HashMap<String, Control>(); 080 081 082 // ~ Constructors 083 // ------------------------------------------------------------------------------- 084 085 /** 086 * Creates a new LdapMessage object. 087 */ 088 public LdapMessageCodec() 089 { 090 super(); 091 // We should not create this kind of object directly 092 093 // Initialize the different known Controls 094 Control control = new PersistentSearchControl(); 095 codecControls.put( control.getOid(), control ); 096 097 control = new ManageDsaITControl(); 098 codecControls.put( control.getOid(), control ); 099 100 control = new SubentriesControl(); 101 codecControls.put( control.getOid(), control ); 102 103 control = new PagedResultsControl(); 104 codecControls.put( control.getOid(), control ); 105 106 control = new SyncDoneValueControl(); 107 codecControls.put( control.getOid(), control ); 108 109 control = new SyncInfoValueControl( SynchronizationInfoEnum.NEW_COOKIE ); 110 codecControls.put( control.getOid(), control ); 111 112 control = new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_DELETE ); 113 codecControls.put( control.getOid(), control ); 114 115 control = new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_PRESENT ); 116 codecControls.put( control.getOid(), control ); 117 118 control = new SyncInfoValueControl( SynchronizationInfoEnum.SYNC_ID_SET ); 119 codecControls.put( control.getOid(), control ); 120 121 control = new SyncRequestValueControl(); 122 codecControls.put( control.getOid(), control ); 123 124 control = new SyncStateValueControl(); 125 codecControls.put( control.getOid(), control ); 126 } 127 128 129 // ~ Methods 130 // ------------------------------------------------------------------------------------ 131 132 /** 133 * Get the Control Object at a specific index 134 * 135 * @param i The index of the Control Object to get 136 * @return The selected Control Object 137 */ 138 public Control getControls( int i ) 139 { 140 if ( controls != null ) 141 { 142 return controls.get( i ); 143 } 144 else 145 { 146 return null; 147 } 148 } 149 150 151 /** 152 * Get the Control Objects 153 * 154 * @return The Control Objects 155 */ 156 public List<Control> getControls() 157 { 158 return controls; 159 } 160 161 162 /** 163 * Get the current Control Object 164 * 165 * @return The current Control Object 166 */ 167 public Control getCurrentControl() 168 { 169 return currentControl; 170 } 171 172 173 public Control getCodecControl( String oid ) 174 { 175 return codecControls.get( oid ); 176 } 177 178 179 /** 180 * Add a control to the Controls array 181 * 182 * @param control The Control to add 183 */ 184 public void addControl( Control control ) 185 { 186 currentControl = control; 187 188 if ( controls == null ) 189 { 190 controls = new ArrayList<Control>(); 191 } 192 193 controls.add( control ); 194 } 195 196 197 /** 198 * Set or add a list of controls to the Controls array. If the existing 199 * control array is not null then the given controls will be added 200 * 201 * @param controls The list of Controls to set or add 202 */ 203 public void addControls( List<Control> controls ) 204 { 205 if( this.controls == null ) 206 { 207 this.controls = controls; 208 } 209 else if( controls != null ) 210 { 211 this.controls.addAll( controls ); 212 } 213 } 214 215 216 /** 217 * Init the controls array 218 */ 219 public void initControls() 220 { 221 controls = new ArrayList<Control>(); 222 } 223 224 225 /** 226 * Get the message ID 227 * 228 * @return The message ID 229 */ 230 public int getMessageId() 231 { 232 return messageId; 233 } 234 235 236 /** 237 * Set the message ID 238 * 239 * @param messageId The message ID 240 */ 241 public void setMessageId( int messageId ) 242 { 243 this.messageId = messageId; 244 } 245 246 247 /** 248 * Get the message type 249 * 250 * @return The message type 251 */ 252 public abstract MessageTypeEnum getMessageType(); 253 254 255 /** 256 * Get the message type Name 257 * 258 * @return The message type name 259 */ 260 public abstract String getMessageTypeName(); 261 262 263 protected abstract int computeLengthProtocolOp(); 264 265 266 /** 267 * Compute the LdapMessage length LdapMessage : 268 * 0x30 L1 269 * | 270 * +--> 0x02 0x0(1-4) [0..2^31-1] (MessageId) 271 * +--> protocolOp 272 * [+--> Controls] 273 * 274 * MessageId length = Length(0x02) + length(MessageId) + MessageId.length 275 * L1 = length(ProtocolOp) 276 * LdapMessage length = Length(0x30) + Length(L1) + MessageId length + L1 277 */ 278 public int computeLength() 279 { 280 // The length of the MessageId. It's the sum of 281 // - the tag (0x02), 1 byte 282 // - the length of the Id length, 1 byte 283 // - the Id length, 1 to 4 bytes 284 ldapMessageLength = 1 + 1 + Value.getNbBytes( messageId ); 285 286 // Get the protocolOp length 287 int protocolOpLength = computeLengthProtocolOp(); 288 289 // Add the protocol length to the message length 290 ldapMessageLength += protocolOpLength; 291 292 // Do the same thing for Controls, if any. 293 if ( controls != null ) 294 { 295 // Controls : 296 // 0xA0 L3 297 // | 298 // +--> 0x30 L4 299 // +--> 0x30 L5 300 // +--> ... 301 // +--> 0x30 Li 302 // +--> ... 303 // +--> 0x30 Ln 304 // 305 // L3 = Length(0x30) + Length(L5) + L5 306 // + Length(0x30) + Length(L6) + L6 307 // + ... 308 // + Length(0x30) + Length(Li) + Li 309 // + ... 310 // + Length(0x30) + Length(Ln) + Ln 311 // 312 // LdapMessageLength = LdapMessageLength + Length(0x90) 313 // + Length(L3) + L3 314 controlsSequenceLength = 0; 315 316 // We may have more than one control. ControlsLength is L4. 317 for ( Control control:controls ) 318 { 319 controlsSequenceLength += ((CodecControl)control).computeLength(); 320 } 321 322 // Computes the controls length 323 controlsLength = controlsSequenceLength; // 1 + Length.getNbBytes( 324 // controlsSequenceLength 325 // ) + controlsSequenceLength; 326 327 // Now, add the tag and the length of the controls length 328 ldapMessageLength += 1 + TLV.getNbBytes( controlsSequenceLength ) + controlsSequenceLength; 329 } 330 331 // finally, calculate the global message size : 332 // length(Tag) + Length(length) + length 333 334 return 1 + ldapMessageLength + TLV.getNbBytes( ldapMessageLength ); 335 } 336 337 338 protected abstract void encodeProtocolOp( ByteBuffer buffer ) throws EncoderException; 339 340 /** 341 * Generate the PDU which contains the encoded object. 342 * 343 * The generation is done in two phases : 344 * - first, we compute the length of each part and the 345 * global PDU length 346 * - second, we produce the PDU. 347 * 348 * <pre> 349 * 0x30 L1 350 * | 351 * +--> 0x02 L2 MessageId 352 * +--> ProtocolOp 353 * +--> Controls 354 * 355 * L2 = Length(MessageId) 356 * L1 = Length(0x02) + Length(L2) + L2 + Length(ProtocolOp) + Length(Controls) 357 * LdapMessageLength = Length(0x30) + Length(L1) + L1 358 * </pre> 359 * 360 * @param buffer The encoded PDU 361 * @return A ByteBuffer that contaons the PDU 362 * @throws EncoderException If anything goes wrong. 363 */ 364 public ByteBuffer encode() throws EncoderException 365 { 366 // Allocate the bytes buffer. 367 ByteBuffer bb = ByteBuffer.allocate( computeLength() ); 368 369 try 370 { 371 // The LdapMessage Sequence 372 bb.put( UniversalTag.SEQUENCE_TAG ); 373 374 // The length has been calculated by the computeLength method 375 bb.put( TLV.getBytes( ldapMessageLength ) ); 376 } 377 catch ( BufferOverflowException boe ) 378 { 379 throw new EncoderException( I18n.err( I18n.ERR_04005 ) ); 380 } 381 382 // The message Id 383 Value.encode( bb, messageId ); 384 385 // Add the protocolOp part 386 encodeProtocolOp( bb ); 387 388 // Do the same thing for Controls, if any. 389 if ( controls != null ) 390 { 391 // Encode the controls 392 bb.put( ( byte ) LdapConstants.CONTROLS_TAG ); 393 bb.put( TLV.getBytes( controlsLength ) ); 394 395 // Encode each control 396 for ( Control control:controls ) 397 { 398 ((CodecControl)control).encode( bb ); 399 } 400 } 401 402 return bb; 403 } 404 405 406 /** 407 * Get a String representation of a LdapMessage 408 * 409 * @return A LdapMessage String 410 */ 411 protected String toString( String protocolOp ) 412 { 413 StringBuffer sb = new StringBuffer(); 414 415 sb.append( "LdapMessage\n" ); 416 sb.append( " message Id : " ).append( messageId ).append( '\n' ); 417 418 sb.append( protocolOp ).append( '\n' ); 419 420 if ( controls != null ) 421 { 422 for ( Control control:controls ) 423 { 424 sb.append( control ); 425 } 426 } 427 428 return sb.toString(); 429 } 430 }