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.LdapCodecConstants; 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 codec The LDAP service instance 080 * @param decoratedMessage the decorated AddRequest 081 */ 082 public AddRequestDecorator( LdapApiService codec, AddRequest decoratedMessage ) 083 { 084 super( codec, decoratedMessage ); 085 } 086 087 088 /** 089 * {@inheritDoc} 090 */ 091 @Override 092 public AddRequest setMessageId( int messageId ) 093 { 094 super.setMessageId( messageId ); 095 096 return this; 097 } 098 099 100 /** 101 * {@inheritDoc} 102 */ 103 @Override 104 public AddRequest addControl( Control control ) 105 { 106 return ( AddRequest ) super.addControl( control ); 107 } 108 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public AddRequest addAllControls( Control[] controls ) 115 { 116 return ( AddRequest ) super.addAllControls( controls ); 117 } 118 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public AddRequest removeControl( Control control ) 125 { 126 return ( AddRequest ) super.removeControl( control ); 127 } 128 129 130 //------------------------------------------------------------------------- 131 // The AddRequest methods 132 //------------------------------------------------------------------------- 133 134 /** 135 * {@inheritDoc} 136 */ 137 @Override 138 public Dn getEntryDn() 139 { 140 return getDecorated().getEntryDn(); 141 } 142 143 144 /** 145 * {@inheritDoc} 146 */ 147 @Override 148 public AddRequest setEntryDn( Dn entry ) 149 { 150 getDecorated().setEntryDn( entry ); 151 152 return this; 153 } 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public Entry getEntry() 161 { 162 return getDecorated().getEntry(); 163 } 164 165 166 /** 167 * {@inheritDoc} 168 */ 169 @Override 170 public AddRequest setEntry( Entry entry ) 171 { 172 getDecorated().setEntry( entry ); 173 174 return this; 175 } 176 177 178 /** 179 * Create a new attributeValue 180 * 181 * @param type The attribute's name (called 'type' in the grammar) 182 * @throws LdapException If the value is invalid 183 */ 184 public void addAttributeType( String type ) throws LdapException 185 { 186 // do not create a new attribute if we have seen this attributeType before 187 if ( getDecorated().getEntry().get( type ) != null ) 188 { 189 currentAttribute = getDecorated().getEntry().get( type ); 190 return; 191 } 192 193 // fix this to use AttributeImpl(type.getString().toLowerCase()) 194 currentAttribute = new DefaultAttribute( type ); 195 getDecorated().getEntry().put( currentAttribute ); 196 } 197 198 199 /** 200 * @return Returns the currentAttribute type. 201 */ 202 public String getCurrentAttributeType() 203 { 204 return currentAttribute.getUpId(); 205 } 206 207 208 /** 209 * Add a new value to the current attribute 210 * 211 * @param value The value to add 212 * @throws LdapException If the value is invalid 213 */ 214 public void addAttributeValue( String value ) throws LdapException 215 { 216 currentAttribute.add( value ); 217 } 218 219 220 /** 221 * Add a new value to the current attribute 222 * 223 * @param value The value to add 224 * @throws LdapException If the value is invalid 225 */ 226 public void addAttributeValue( Value<?> value ) throws LdapException 227 { 228 currentAttribute.add( value ); 229 } 230 231 232 /** 233 * Add a new value to the current attribute 234 * 235 * @param value The value to add 236 * @throws LdapException If the value is invalid 237 */ 238 public void addAttributeValue( byte[] value ) throws LdapException 239 { 240 currentAttribute.add( value ); 241 } 242 243 244 //------------------------------------------------------------------------- 245 // The Decorator methods 246 //------------------------------------------------------------------------- 247 /** 248 * Compute the AddRequest length 249 * <br> 250 * AddRequest : 251 * <pre> 252 * 0x68 L1 253 * | 254 * +--> 0x04 L2 entry 255 * +--> 0x30 L3 (attributes) 256 * | 257 * +--> 0x30 L4-1 (attribute) 258 * | | 259 * | +--> 0x04 L5-1 type 260 * | +--> 0x31 L6-1 (values) 261 * | | 262 * | +--> 0x04 L7-1-1 value 263 * | +--> ... 264 * | +--> 0x04 L7-1-n value 265 * | 266 * +--> 0x30 L4-2 (attribute) 267 * | | 268 * | +--> 0x04 L5-2 type 269 * | +--> 0x31 L6-2 (values) 270 * | | 271 * | +--> 0x04 L7-2-1 value 272 * | +--> ... 273 * | +--> 0x04 L7-2-n value 274 * | 275 * +--> ... 276 * | 277 * +--> 0x30 L4-m (attribute) 278 * | 279 * +--> 0x04 L5-m type 280 * +--> 0x31 L6-m (values) 281 * | 282 * +--> 0x04 L7-m-1 value 283 * +--> ... 284 * +--> 0x04 L7-m-n value 285 * </pre> 286 */ 287 @Override 288 public int computeLength() 289 { 290 AddRequest addRequest = getDecorated(); 291 Entry entry = addRequest.getEntry(); 292 293 if ( entry == null ) 294 { 295 throw new IllegalArgumentException( I18n.err( I18n.ERR_04481_ENTRY_NULL_VALUE ) ); 296 } 297 298 dnBytes = Strings.getBytesUtf8( entry.getDn().getName() ); 299 int dnLen = dnBytes.length; 300 301 // The entry Dn 302 addRequestLength = 1 + TLV.getNbBytes( dnLen ) + dnLen; 303 304 // The attributes sequence 305 entryLength = 0; 306 307 if ( entry.size() != 0 ) 308 { 309 attributesLength = new LinkedList<>(); 310 attributeIds = new LinkedList<>(); 311 valuesLength = new LinkedList<>(); 312 313 // Compute the attributes length 314 for ( Attribute attribute : entry ) 315 { 316 int localAttributeLength; 317 int localValuesLength; 318 319 // Get the type length 320 byte[] attributeIdBytes = Strings.getBytesUtf8( attribute.getUpId() ); 321 attributeIds.add( attributeIdBytes ); 322 323 int idLength = attributeIdBytes.length; 324 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength; 325 326 // The values 327 if ( attribute.size() != 0 ) 328 { 329 localValuesLength = 0; 330 331 for ( Value<?> value : attribute ) 332 { 333 if ( value.getBytes() == null ) 334 { 335 localValuesLength += 1 + 1; 336 } 337 else 338 { 339 int valueLength = value.getBytes().length; 340 localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength; 341 } 342 } 343 344 localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength; 345 } 346 else 347 { 348 // No value : we still have to store the encapsulating Sequence 349 localValuesLength = 1 + 1; 350 localAttributeLength += 1 + 1 + localValuesLength; 351 } 352 353 // add the attribute length to the attributes length 354 entryLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength; 355 356 attributesLength.add( localAttributeLength ); 357 valuesLength.add( localValuesLength ); 358 } 359 } 360 361 addRequestLength += 1 + TLV.getNbBytes( entryLength ) + entryLength; 362 363 // Return the result. 364 return 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength; 365 } 366 367 368 /** 369 * Encode the AddRequest message to a PDU. 370 * <br> 371 * AddRequest : 372 * <pre> 373 * 0x68 LL 374 * 0x04 LL entry 375 * 0x30 LL attributesList 376 * 0x30 LL attributeList 377 * 0x04 LL attributeDescription 378 * 0x31 LL attributeValues 379 * 0x04 LL attributeValue 380 * ... 381 * 0x04 LL attributeValue 382 * ... 383 * 0x30 LL attributeList 384 * 0x04 LL attributeDescription 385 * 0x31 LL attributeValue 386 * 0x04 LL attributeValue 387 * ... 388 * 0x04 LL attributeValue 389 * </pre> 390 * 391 * @param buffer The buffer where to put the PDU 392 */ 393 @Override 394 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 395 { 396 try 397 { 398 // The AddRequest Tag 399 buffer.put( LdapCodecConstants.ADD_REQUEST_TAG ); 400 buffer.put( TLV.getBytes( addRequestLength ) ); 401 402 // The entry 403 BerValue.encode( buffer, dnBytes ); 404 405 // The attributes sequence 406 buffer.put( UniversalTag.SEQUENCE.getValue() ); 407 buffer.put( TLV.getBytes( entryLength ) ); 408 409 // The partial attribute list 410 Entry entry = getEntry(); 411 412 if ( entry.size() != 0 ) 413 { 414 int attributeNumber = 0; 415 416 // Compute the attributes length 417 for ( Attribute attribute : entry ) 418 { 419 // The attributes list sequence 420 buffer.put( UniversalTag.SEQUENCE.getValue() ); 421 int localAttributeLength = attributesLength.get( attributeNumber ); 422 buffer.put( TLV.getBytes( localAttributeLength ) ); 423 424 // The attribute type 425 BerValue.encode( buffer, attributeIds.get( attributeNumber ) ); 426 427 // The values 428 buffer.put( UniversalTag.SET.getValue() ); 429 int localValuesLength = valuesLength.get( attributeNumber ); 430 buffer.put( TLV.getBytes( localValuesLength ) ); 431 432 if ( attribute.size() != 0 ) 433 { 434 for ( Value<?> value : attribute ) 435 { 436 BerValue.encode( buffer, value.getBytes() ); 437 } 438 } 439 else 440 { 441 BerValue.encode( buffer, Strings.EMPTY_BYTES ); 442 } 443 444 // Go to the next attribute number 445 attributeNumber++; 446 } 447 } 448 449 return buffer; 450 } 451 catch ( BufferOverflowException boe ) 452 { 453 throw new EncoderException( "The PDU buffer size is too small !", boe ); 454 } 455 } 456}