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