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.Collection; 026import java.util.LinkedList; 027import java.util.List; 028 029import org.apache.directory.api.asn1.EncoderException; 030import org.apache.directory.api.asn1.ber.tlv.BerValue; 031import org.apache.directory.api.asn1.ber.tlv.TLV; 032import org.apache.directory.api.asn1.ber.tlv.UniversalTag; 033import org.apache.directory.api.i18n.I18n; 034import org.apache.directory.api.ldap.codec.api.LdapApiService; 035import org.apache.directory.api.ldap.codec.api.LdapConstants; 036import org.apache.directory.api.ldap.model.entry.Attribute; 037import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 038import org.apache.directory.api.ldap.model.entry.DefaultModification; 039import org.apache.directory.api.ldap.model.entry.Modification; 040import org.apache.directory.api.ldap.model.entry.ModificationOperation; 041import org.apache.directory.api.ldap.model.entry.Value; 042import org.apache.directory.api.ldap.model.exception.LdapException; 043import org.apache.directory.api.ldap.model.message.Control; 044import org.apache.directory.api.ldap.model.message.ModifyRequest; 045import org.apache.directory.api.ldap.model.name.Dn; 046 047 048/** 049 * A decorator for the ModifyRequest message 050 * 051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 052 */ 053public class ModifyRequestDecorator extends SingleReplyRequestDecorator<ModifyRequest> 054 implements ModifyRequest 055{ 056 /** The modify request length */ 057 private int modifyRequestLength; 058 059 /** The changes length */ 060 private int changesLength; 061 062 /** The list of all change lengths */ 063 private List<Integer> changeLength = new LinkedList<Integer>(); 064 065 /** The list of all the modification lengths */ 066 private List<Integer> modificationLength = new LinkedList<Integer>(); 067 068 /** The list of all the value lengths */ 069 private List<Integer> valuesLength = new LinkedList<Integer>(); 070 071 /** The current attribute being decoded */ 072 private Attribute currentAttribute; 073 074 /** A local storage for the operation */ 075 private ModificationOperation currentOperation; 076 077 078 /** 079 * Makes a ModifyRequest encodable. 080 * 081 * @param decoratedMessage the decorated ModifyRequest 082 */ 083 public ModifyRequestDecorator( LdapApiService codec, ModifyRequest decoratedMessage ) 084 { 085 super( codec, decoratedMessage ); 086 } 087 088 089 /** 090 * @param modifyRequestLength The encoded ModifyRequest's length 091 */ 092 public void setModifyRequestLength( int modifyRequestLength ) 093 { 094 this.modifyRequestLength = modifyRequestLength; 095 } 096 097 098 /** 099 * @return The encoded length 100 */ 101 public int getModifyRequestLength() 102 { 103 return modifyRequestLength; 104 } 105 106 107 /** 108 * @param changesLength The encoded Changes length 109 */ 110 public void setChangesLength( int changesLength ) 111 { 112 this.changesLength = changesLength; 113 } 114 115 116 /** 117 * @return The encoded length 118 */ 119 public int getChangesLength() 120 { 121 return changesLength; 122 } 123 124 125 /** 126 * @return The list of encoded Change length 127 */ 128 public void setChangeLength( List<Integer> changeLength ) 129 { 130 this.changeLength = changeLength; 131 } 132 133 134 /** 135 * @return The list of encoded Change length 136 */ 137 public List<Integer> getChangeLength() 138 { 139 return changeLength; 140 } 141 142 143 /** 144 * @param modificationLength The list of encoded Modification length 145 */ 146 public void setModificationLength( List<Integer> modificationLength ) 147 { 148 this.modificationLength = modificationLength; 149 } 150 151 152 /** 153 * @return The list of encoded Modification length 154 */ 155 public List<Integer> getModificationLength() 156 { 157 return modificationLength; 158 } 159 160 161 /** 162 * @param valuesLength The list of encoded Values length 163 */ 164 public void setValuesLength( List<Integer> valuesLength ) 165 { 166 this.valuesLength = valuesLength; 167 } 168 169 170 /** 171 * @return The list of encoded Values length 172 */ 173 public List<Integer> getValuesLength() 174 { 175 return valuesLength; 176 } 177 178 179 /** 180 * Store the current operation 181 * 182 * @param currentOperation The currentOperation to set. 183 */ 184 public void setCurrentOperation( int currentOperation ) 185 { 186 this.currentOperation = ModificationOperation.getOperation( currentOperation ); 187 } 188 189 190 /** 191 * Add a new attributeTypeAndValue 192 * 193 * @param type The attribute's name 194 */ 195 public void addAttributeTypeAndValues( String type ) 196 { 197 currentAttribute = new DefaultAttribute( type ); 198 199 Modification modification = new DefaultModification( currentOperation, currentAttribute ); 200 getDecorated().addModification( modification ); 201 } 202 203 204 /** 205 * Return the current attribute's type 206 */ 207 public String getCurrentAttributeType() 208 { 209 return currentAttribute.getUpId(); 210 } 211 212 213 /** 214 * Add a new value to the current attribute 215 * 216 * @param value The value to add 217 */ 218 public void addAttributeValue( byte[] value ) throws LdapException 219 { 220 currentAttribute.add( value ); 221 } 222 223 224 /** 225 * Add a new value to the current attribute 226 * 227 * @param value The value to add 228 */ 229 public void addAttributeValue( String value ) throws LdapException 230 { 231 currentAttribute.add( value ); 232 } 233 234 235 //------------------------------------------------------------------------- 236 // The ModifyRequest methods 237 //------------------------------------------------------------------------- 238 239 /** 240 * {@inheritDoc} 241 */ 242 public Dn getName() 243 { 244 return getDecorated().getName(); 245 } 246 247 248 /** 249 * {@inheritDoc} 250 */ 251 public ModifyRequest setName( Dn name ) 252 { 253 getDecorated().setName( name ); 254 255 return this; 256 } 257 258 259 /** 260 * {@inheritDoc} 261 */ 262 public Collection<Modification> getModifications() 263 { 264 return getDecorated().getModifications(); 265 } 266 267 268 /** 269 * {@inheritDoc} 270 */ 271 public ModifyRequest addModification( Modification mod ) 272 { 273 getDecorated().addModification( mod ); 274 275 return this; 276 } 277 278 279 /** 280 * {@inheritDoc} 281 */ 282 public ModifyRequest removeModification( Modification mod ) 283 { 284 getDecorated().removeModification( mod ); 285 286 return this; 287 } 288 289 290 /** 291 * {@inheritDoc} 292 */ 293 public ModifyRequest remove( String attributeName, String... attributeValue ) 294 { 295 getDecorated().remove( attributeName, attributeValue ); 296 297 return this; 298 } 299 300 301 /** 302 * {@inheritDoc} 303 */ 304 public ModifyRequest remove( String attributeName, byte[]... attributeValue ) 305 { 306 getDecorated().remove( attributeName, attributeValue ); 307 308 return this; 309 } 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 public ModifyRequest remove( Attribute attr ) 316 { 317 getDecorated().remove( attr ); 318 319 return this; 320 } 321 322 323 /** 324 * {@inheritDoc} 325 */ 326 public ModifyRequest addModification( Attribute attr, ModificationOperation modOp ) 327 { 328 getDecorated().addModification( attr, modOp ); 329 330 return this; 331 } 332 333 334 /** 335 * {@inheritDoc} 336 */ 337 public ModifyRequest add( String attributeName, String... attributeValue ) 338 { 339 getDecorated().add( attributeName, attributeValue ); 340 341 return this; 342 } 343 344 345 /** 346 * {@inheritDoc} 347 */ 348 public ModifyRequest add( String attributeName, byte[]... attributeValue ) 349 { 350 getDecorated().add( attributeName, attributeValue ); 351 352 return this; 353 } 354 355 356 /** 357 * {@inheritDoc} 358 */ 359 public ModifyRequest add( Attribute attr ) 360 { 361 getDecorated().add( attr ); 362 363 return this; 364 } 365 366 367 /** 368 * {@inheritDoc} 369 */ 370 public ModifyRequest replace( String attributeName ) 371 { 372 getDecorated().replace( attributeName ); 373 374 return this; 375 } 376 377 378 /** 379 * {@inheritDoc} 380 */ 381 public ModifyRequest replace( String attributeName, String... attributeValue ) 382 { 383 getDecorated().replace( attributeName, attributeValue ); 384 385 return this; 386 } 387 388 389 /** 390 * {@inheritDoc} 391 */ 392 public ModifyRequest replace( String attributeName, byte[]... attributeValue ) 393 { 394 getDecorated().replace( attributeName, attributeValue ); 395 396 return this; 397 } 398 399 400 /** 401 * {@inheritDoc} 402 */ 403 public ModifyRequest replace( Attribute attr ) 404 { 405 getDecorated().replace( attr ); 406 407 return this; 408 } 409 410 411 /** 412 * {@inheritDoc} 413 */ 414 public ModifyRequest setMessageId( int messageId ) 415 { 416 super.setMessageId( messageId ); 417 418 return this; 419 } 420 421 422 /** 423 * {@inheritDoc} 424 */ 425 public ModifyRequest addControl( Control control ) 426 { 427 return ( ModifyRequest ) super.addControl( control ); 428 } 429 430 431 /** 432 * {@inheritDoc} 433 */ 434 public ModifyRequest addAllControls( Control[] controls ) 435 { 436 return ( ModifyRequest ) super.addAllControls( controls ); 437 } 438 439 440 /** 441 * {@inheritDoc} 442 */ 443 public ModifyRequest removeControl( Control control ) 444 { 445 return ( ModifyRequest ) super.removeControl( control ); 446 } 447 448 449 //------------------------------------------------------------------------- 450 // The Decorator methods 451 //------------------------------------------------------------------------- 452 453 /** 454 * Compute the ModifyRequest length 455 * 456 * ModifyRequest : 457 * 458 * 0x66 L1 459 * | 460 * +--> 0x04 L2 object 461 * +--> 0x30 L3 modifications 462 * | 463 * +--> 0x30 L4-1 modification sequence 464 * | | 465 * | +--> 0x0A 0x01 (0..2) operation 466 * | +--> 0x30 L5-1 modification 467 * | | 468 * | +--> 0x04 L6-1 type 469 * | +--> 0x31 L7-1 vals 470 * | | 471 * | +--> 0x04 L8-1-1 attributeValue 472 * | +--> 0x04 L8-1-2 attributeValue 473 * | +--> ... 474 * | +--> 0x04 L8-1-i attributeValue 475 * | +--> ... 476 * | +--> 0x04 L8-1-n attributeValue 477 * | 478 * +--> 0x30 L4-2 modification sequence 479 * . | 480 * . +--> 0x0A 0x01 (0..2) operation 481 * . +--> 0x30 L5-2 modification 482 * | 483 * +--> 0x04 L6-2 type 484 * +--> 0x31 L7-2 vals 485 * | 486 * +--> 0x04 L8-2-1 attributeValue 487 * +--> 0x04 L8-2-2 attributeValue 488 * +--> ... 489 * +--> 0x04 L8-2-i attributeValue 490 * +--> ... 491 * +--> 0x04 L8-2-n attributeValue 492 */ 493 public int computeLength() 494 { 495 // Initialized with name 496 int modifyRequestLength = 1 + TLV.getNbBytes( Dn.getNbBytes( getName() ) ) 497 + Dn.getNbBytes( getName() ); 498 499 // All the changes length 500 int changesLength = 0; 501 502 Collection<Modification> modifications = getModifications(); 503 504 if ( ( modifications != null ) && ( modifications.size() != 0 ) ) 505 { 506 List<Integer> changeLength = new LinkedList<Integer>(); 507 List<Integer> modificationLength = new LinkedList<Integer>(); 508 List<Integer> valuesLength = new LinkedList<Integer>(); 509 510 for ( Modification modification : modifications ) 511 { 512 // Modification sequence length initialized with the operation 513 int localModificationSequenceLength = 1 + 1 + 1; 514 int localValuesLength = 0; 515 516 // Modification length initialized with the type 517 int typeLength = modification.getAttribute().getUpId().length(); 518 int localModificationLength = 1 + TLV.getNbBytes( typeLength ) + typeLength; 519 520 // Get all the values 521 if ( modification.getAttribute().size() != 0 ) 522 { 523 for ( Value<?> value : modification.getAttribute() ) 524 { 525 localValuesLength += 1 + TLV.getNbBytes( value.getBytes().length ) + value.getBytes().length; 526 } 527 } 528 529 localModificationLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength; 530 531 // Compute the modificationSequenceLength 532 localModificationSequenceLength += 1 + TLV.getNbBytes( localModificationLength ) 533 + localModificationLength; 534 535 // Add the tag and the length 536 changesLength += 1 + TLV.getNbBytes( localModificationSequenceLength ) 537 + localModificationSequenceLength; 538 539 // Store the arrays of values 540 valuesLength.add( localValuesLength ); 541 modificationLength.add( localModificationLength ); 542 changeLength.add( localModificationSequenceLength ); 543 } 544 545 // Add the modifications length to the modificationRequestLength 546 modifyRequestLength += 1 + TLV.getNbBytes( changesLength ) + changesLength; 547 setChangeLength( changeLength ); 548 setModificationLength( modificationLength ); 549 setValuesLength( valuesLength ); 550 } 551 552 setChangesLength( changesLength ); 553 setModifyRequestLength( modifyRequestLength ); 554 555 return 1 + TLV.getNbBytes( modifyRequestLength ) + modifyRequestLength; 556 } 557 558 559 /** 560 * Encode the ModifyRequest message to a PDU. 561 * 562 * ModifyRequest : 563 * <pre> 564 * 0x66 LL 565 * 0x04 LL object 566 * 0x30 LL modifiations 567 * 0x30 LL modification sequence 568 * 0x0A 0x01 operation 569 * 0x30 LL modification 570 * 0x04 LL type 571 * 0x31 LL vals 572 * 0x04 LL attributeValue 573 * ... 574 * 0x04 LL attributeValue 575 * ... 576 * 0x30 LL modification sequence 577 * 0x0A 0x01 operation 578 * 0x30 LL modification 579 * 0x04 LL type 580 * 0x31 LL vals 581 * 0x04 LL attributeValue 582 * ... 583 * 0x04 LL attributeValue 584 * </pre> 585 * 586 * @param buffer The buffer where to put the PDU 587 * @return The PDU. 588 */ 589 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 590 { 591 try 592 { 593 // The AddRequest Tag 594 buffer.put( LdapConstants.MODIFY_REQUEST_TAG ); 595 buffer.put( TLV.getBytes( getModifyRequestLength() ) ); 596 597 // The entry 598 BerValue.encode( buffer, Dn.getBytes( getName() ) ); 599 600 // The modifications sequence 601 buffer.put( UniversalTag.SEQUENCE.getValue() ); 602 buffer.put( TLV.getBytes( getChangesLength() ) ); 603 604 // The modifications list 605 Collection<Modification> modifications = getModifications(); 606 607 if ( ( modifications != null ) && ( modifications.size() != 0 ) ) 608 { 609 int modificationNumber = 0; 610 611 // Compute the modifications length 612 for ( Modification modification : modifications ) 613 { 614 // The modification sequence 615 buffer.put( UniversalTag.SEQUENCE.getValue() ); 616 int localModificationSequenceLength = getChangeLength().get( modificationNumber ); 617 buffer.put( TLV.getBytes( localModificationSequenceLength ) ); 618 619 // The operation. The value has to be changed, it's not 620 // the same value in DirContext and in RFC 2251. 621 buffer.put( UniversalTag.ENUMERATED.getValue() ); 622 buffer.put( ( byte ) 1 ); 623 buffer.put( ( byte ) modification.getOperation().getValue() ); 624 625 // The modification 626 buffer.put( UniversalTag.SEQUENCE.getValue() ); 627 int localModificationLength = getModificationLength().get( modificationNumber ); 628 buffer.put( TLV.getBytes( localModificationLength ) ); 629 630 // The modification type 631 BerValue.encode( buffer, modification.getAttribute().getUpId() ); 632 633 // The values 634 buffer.put( UniversalTag.SET.getValue() ); 635 int localValuesLength = getValuesLength().get( modificationNumber ); 636 buffer.put( TLV.getBytes( localValuesLength ) ); 637 638 if ( modification.getAttribute().size() != 0 ) 639 { 640 for ( org.apache.directory.api.ldap.model.entry.Value<?> value : modification.getAttribute() ) 641 { 642 if ( value.isHumanReadable() ) 643 { 644 BerValue.encode( buffer, value.getString() ); 645 } 646 else 647 { 648 BerValue.encode( buffer, value.getBytes() ); 649 } 650 } 651 } 652 653 // Go to the next modification number; 654 modificationNumber++; 655 } 656 } 657 } 658 catch ( BufferOverflowException boe ) 659 { 660 throw new EncoderException( I18n.err( I18n.ERR_04005 ) ); 661 } 662 663 return buffer; 664 } 665}