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