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.codec.decorators; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025import java.util.LinkedList; 026import java.util.List; 027 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.LdapApiService; 034import org.apache.directory.api.ldap.codec.api.LdapConstants; 035import org.apache.directory.api.ldap.model.entry.Attribute; 036import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 037import org.apache.directory.api.ldap.model.entry.Entry; 038import org.apache.directory.api.ldap.model.entry.Value; 039import org.apache.directory.api.ldap.model.exception.LdapException; 040import org.apache.directory.api.ldap.model.message.AddRequest; 041import org.apache.directory.api.ldap.model.message.Control; 042import org.apache.directory.api.ldap.model.name.Dn; 043import org.apache.directory.api.util.Strings; 044 045 046/** 047 * A decorator for the AddRequest message 048 * 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051public final class AddRequestDecorator extends SingleReplyRequestDecorator<AddRequest> implements 052 AddRequest 053{ 054 /** The add request length */ 055 private int addRequestLength; 056 057 /** The Entry length */ 058 private int entryLength; 059 060 /** The list of all attributes length */ 061 private List<Integer> attributesLength; 062 063 /** The list of all attributes Id bytes */ 064 private List<byte[]> attributeIds; 065 066 /** The list of all vals length */ 067 private List<Integer> valuesLength; 068 069 /** The current attribute being decoded */ 070 private Attribute currentAttribute; 071 072 /** The bytes containing the Dn */ 073 private byte[] dnBytes; 074 075 076 /** 077 * Makes a AddRequest a MessageDecorator. 078 * 079 * @param decoratedMessage the decorated AddRequest 080 */ 081 public AddRequestDecorator( LdapApiService codec, AddRequest decoratedMessage ) 082 { 083 super( codec, decoratedMessage ); 084 } 085 086 087 /** 088 * Stores the encoded length for the AddRequest 089 * @param addRequestLength The encoded length 090 */ 091 public void setAddRequestLength( int addRequestLength ) 092 { 093 this.addRequestLength = addRequestLength; 094 } 095 096 097 /** 098 * @return The encoded AddRequest's length 099 */ 100 public int getAddRequestLength() 101 { 102 return addRequestLength; 103 } 104 105 106 /** 107 * Stores the encoded length for the Entry 108 * @param entryLength The encoded length 109 */ 110 public void setEntryLength( int entryLength ) 111 { 112 this.entryLength = entryLength; 113 } 114 115 116 /** 117 * @return The encoded Entry's length 118 */ 119 public int getEntryLength() 120 { 121 return entryLength; 122 } 123 124 125 /** 126 * Stores the encoded length for the attributes 127 * @param attributesLength The encoded length 128 */ 129 public void setAttributesLength( List<Integer> attributesLength ) 130 { 131 this.attributesLength = attributesLength; 132 } 133 134 135 /** 136 * @return The encoded values length 137 */ 138 public List<Integer> getAttributesLength() 139 { 140 return attributesLength; 141 } 142 143 144 /** 145 * Stores the encoded length for the values 146 * @param valuesLength The encoded length 147 */ 148 public void setValuesLength( List<Integer> valuesLength ) 149 { 150 this.valuesLength = valuesLength; 151 } 152 153 154 /** 155 * @return The encoded values length 156 */ 157 public List<Integer> getValuesLength() 158 { 159 return valuesLength; 160 } 161 162 163 /** 164 * {@inheritDoc} 165 */ 166 public AddRequest setMessageId( int messageId ) 167 { 168 super.setMessageId( messageId ); 169 170 return this; 171 } 172 173 174 /** 175 * {@inheritDoc} 176 */ 177 public AddRequest addControl( Control control ) 178 { 179 return ( AddRequest ) super.addControl( control ); 180 } 181 182 183 /** 184 * {@inheritDoc} 185 */ 186 public AddRequest addAllControls( Control[] controls ) 187 { 188 return ( AddRequest ) super.addAllControls( controls ); 189 } 190 191 192 /** 193 * {@inheritDoc} 194 */ 195 public AddRequest removeControl( Control control ) 196 { 197 return ( AddRequest ) super.removeControl( control ); 198 } 199 200 201 //------------------------------------------------------------------------- 202 // The AddRequest methods 203 //------------------------------------------------------------------------- 204 205 /** 206 * {@inheritDoc} 207 */ 208 public Dn getEntryDn() 209 { 210 return getDecorated().getEntryDn(); 211 } 212 213 214 /** 215 * {@inheritDoc} 216 */ 217 public AddRequest setEntryDn( Dn entry ) 218 { 219 getDecorated().setEntryDn( entry ); 220 221 return this; 222 } 223 224 225 /** 226 * {@inheritDoc} 227 */ 228 public Entry getEntry() 229 { 230 return getDecorated().getEntry(); 231 } 232 233 234 /** 235 * {@inheritDoc} 236 */ 237 public AddRequest setEntry( Entry entry ) 238 { 239 getDecorated().setEntry( entry ); 240 241 return this; 242 } 243 244 245 /** 246 * Create a new attributeValue 247 * 248 * @param type The attribute's name (called 'type' in the grammar) 249 */ 250 public void addAttributeType( String type ) throws LdapException 251 { 252 // do not create a new attribute if we have seen this attributeType before 253 if ( getDecorated().getEntry().get( type ) != null ) 254 { 255 currentAttribute = getDecorated().getEntry().get( type ); 256 return; 257 } 258 259 // fix this to use AttributeImpl(type.getString().toLowerCase()) 260 currentAttribute = new DefaultAttribute( type ); 261 getDecorated().getEntry().put( currentAttribute ); 262 } 263 264 265 /** 266 * @return Returns the currentAttribute type. 267 */ 268 public String getCurrentAttributeType() 269 { 270 return currentAttribute.getUpId(); 271 } 272 273 274 /** 275 * Add a new value to the current attribute 276 * 277 * @param value The value to add 278 */ 279 public void addAttributeValue( String value ) throws LdapException 280 { 281 currentAttribute.add( value ); 282 } 283 284 285 /** 286 * Add a new value to the current attribute 287 * 288 * @param value The value to add 289 */ 290 public void addAttributeValue( Value<?> value ) throws LdapException 291 { 292 currentAttribute.add( value ); 293 } 294 295 296 /** 297 * Add a new value to the current attribute 298 * 299 * @param value The value to add 300 */ 301 public void addAttributeValue( byte[] value ) throws LdapException 302 { 303 currentAttribute.add( value ); 304 } 305 306 307 //------------------------------------------------------------------------- 308 // The Decorator methods 309 //------------------------------------------------------------------------- 310 /** 311 * Compute the AddRequest length 312 * 313 * AddRequest : 314 * 315 * 0x68 L1 316 * | 317 * +--> 0x04 L2 entry 318 * +--> 0x30 L3 (attributes) 319 * | 320 * +--> 0x30 L4-1 (attribute) 321 * | | 322 * | +--> 0x04 L5-1 type 323 * | +--> 0x31 L6-1 (values) 324 * | | 325 * | +--> 0x04 L7-1-1 value 326 * | +--> ... 327 * | +--> 0x04 L7-1-n value 328 * | 329 * +--> 0x30 L4-2 (attribute) 330 * | | 331 * | +--> 0x04 L5-2 type 332 * | +--> 0x31 L6-2 (values) 333 * | | 334 * | +--> 0x04 L7-2-1 value 335 * | +--> ... 336 * | +--> 0x04 L7-2-n value 337 * | 338 * +--> ... 339 * | 340 * +--> 0x30 L4-m (attribute) 341 * | 342 * +--> 0x04 L5-m type 343 * +--> 0x31 L6-m (values) 344 * | 345 * +--> 0x04 L7-m-1 value 346 * +--> ... 347 * +--> 0x04 L7-m-n value 348 */ 349 public int computeLength() 350 { 351 AddRequest addRequest = getDecorated(); 352 Entry entry = addRequest.getEntry(); 353 354 if ( entry == null ) 355 { 356 throw new IllegalArgumentException( I18n.err( I18n.ERR_04481_ENTRY_NULL_VALUE ) ); 357 } 358 359 dnBytes = Strings.getBytesUtf8( entry.getDn().getName() ); 360 int dnLen = dnBytes.length; 361 362 // The entry Dn 363 int addRequestLength = 1 + TLV.getNbBytes( dnLen ) + dnLen; 364 365 // The attributes sequence 366 int entryLength = 0; 367 368 if ( entry.size() != 0 ) 369 { 370 attributesLength = new LinkedList<Integer>(); 371 attributeIds = new LinkedList<byte[]>(); 372 valuesLength = new LinkedList<Integer>(); 373 374 // Compute the attributes length 375 for ( Attribute attribute : entry ) 376 { 377 int localAttributeLength = 0; 378 int localValuesLength = 0; 379 380 // Get the type length 381 byte[] attributeIdBytes = Strings.getBytesUtf8( attribute.getUpId() ); 382 attributeIds.add( attributeIdBytes ); 383 384 int idLength = attributeIdBytes.length; 385 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength; 386 387 // The values 388 if ( attribute.size() != 0 ) 389 { 390 localValuesLength = 0; 391 392 for ( Value<?> value : attribute ) 393 { 394 if ( value.getBytes() == null ) 395 { 396 localValuesLength += 1 + 1; 397 } 398 else 399 { 400 int valueLength = value.getBytes().length; 401 localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength; 402 } 403 } 404 405 localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength; 406 } 407 else 408 { 409 // No value : we still have to store the encapsulating Sequence 410 localValuesLength = 1 + 1; 411 localAttributeLength += 1 + 1 + localValuesLength; 412 } 413 414 // add the attribute length to the attributes length 415 entryLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength; 416 417 attributesLength.add( localAttributeLength ); 418 valuesLength.add( localValuesLength ); 419 } 420 421 setAttributesLength( attributesLength ); 422 setValuesLength( valuesLength ); 423 setEntryLength( entryLength ); 424 } 425 426 addRequestLength += 1 + TLV.getNbBytes( entryLength ) + entryLength; 427 setAddRequestLength( addRequestLength ); 428 429 // Return the result. 430 return 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength; 431 } 432 433 434 /** 435 * Encode the AddRequest message to a PDU. 436 * 437 * AddRequest : 438 * 439 * 0x68 LL 440 * 0x04 LL entry 441 * 0x30 LL attributesList 442 * 0x30 LL attributeList 443 * 0x04 LL attributeDescription 444 * 0x31 LL attributeValues 445 * 0x04 LL attributeValue 446 * ... 447 * 0x04 LL attributeValue 448 * ... 449 * 0x30 LL attributeList 450 * 0x04 LL attributeDescription 451 * 0x31 LL attributeValue 452 * 0x04 LL attributeValue 453 * ... 454 * 0x04 LL attributeValue 455 * 456 * @param buffer The buffer where to put the PDU 457 */ 458 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 459 { 460 try 461 { 462 // The AddRequest Tag 463 buffer.put( LdapConstants.ADD_REQUEST_TAG ); 464 buffer.put( TLV.getBytes( getAddRequestLength() ) ); 465 466 // The entry 467 BerValue.encode( buffer, dnBytes ); 468 469 // The attributes sequence 470 buffer.put( UniversalTag.SEQUENCE.getValue() ); 471 buffer.put( TLV.getBytes( getEntryLength() ) ); 472 473 // The partial attribute list 474 Entry entry = getEntry(); 475 476 if ( entry.size() != 0 ) 477 { 478 int attributeNumber = 0; 479 480 // Compute the attributes length 481 for ( Attribute attribute : entry ) 482 { 483 // The attributes list sequence 484 buffer.put( UniversalTag.SEQUENCE.getValue() ); 485 int localAttributeLength = attributesLength.get( attributeNumber ); 486 buffer.put( TLV.getBytes( localAttributeLength ) ); 487 488 // The attribute type 489 BerValue.encode( buffer, attributeIds.get( attributeNumber ) ); 490 491 // The values 492 buffer.put( UniversalTag.SET.getValue() ); 493 int localValuesLength = valuesLength.get( attributeNumber ); 494 buffer.put( TLV.getBytes( localValuesLength ) ); 495 496 if ( attribute.size() != 0 ) 497 { 498 for ( Value<?> value : attribute ) 499 { 500 BerValue.encode( buffer, value.getBytes() ); 501 } 502 } 503 else 504 { 505 BerValue.encode( buffer, Strings.EMPTY_BYTES ); 506 } 507 508 // Go to the next attribute number; 509 attributeNumber++; 510 } 511 } 512 513 return buffer; 514 } 515 catch ( BufferOverflowException boe ) 516 { 517 throw new EncoderException( "The PDU buffer size is too small !" ); 518 } 519 } 520}