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 */ 020 package org.apache.directory.shared.ldap.codec.add; 021 022 023 import java.nio.BufferOverflowException; 024 import java.nio.ByteBuffer; 025 import java.util.LinkedList; 026 import java.util.List; 027 028 import org.apache.directory.shared.ldap.exception.LdapException; 029 030 import org.apache.directory.shared.asn1.ber.tlv.TLV; 031 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 032 import org.apache.directory.shared.asn1.ber.tlv.Value; 033 import org.apache.directory.shared.asn1.codec.EncoderException; 034 import org.apache.directory.shared.ldap.codec.LdapConstants; 035 import org.apache.directory.shared.ldap.codec.LdapMessageCodec; 036 import org.apache.directory.shared.ldap.codec.MessageTypeEnum; 037 import org.apache.directory.shared.ldap.entry.Entry; 038 import org.apache.directory.shared.ldap.entry.EntryAttribute; 039 import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute; 040 import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry; 041 import org.apache.directory.shared.ldap.name.DN; 042 import org.apache.directory.shared.ldap.util.StringTools; 043 import org.slf4j.Logger; 044 import org.slf4j.LoggerFactory; 045 046 047 /** 048 * An AddRequest Message. Its syntax is : 049 * AddRequest ::= [APPLICATION 8] SEQUENCE { 050 * entry LDAPDN, 051 * attributes AttributeList } 052 * 053 * AttributeList ::= SEQUENCE OF SEQUENCE { 054 * type AttributeDescription, 055 * vals SET OF AttributeValue } 056 * 057 * AttributeValue ::= OCTET STRING 058 * 059 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 060 * @version $Rev: 923524 $, $Date: 2010-03-16 01:31:36 +0100 (Tue, 16 Mar 2010) $, 061 */ 062 public class AddRequestCodec extends LdapMessageCodec 063 { 064 // ~ Static fields/initializers 065 // ----------------------------------------------------------------- 066 067 /** The logger */ 068 private static final Logger log = LoggerFactory.getLogger( AddRequestCodec.class ); 069 070 /** Speedup for logs */ 071 private static final boolean IS_DEBUG = log.isDebugEnabled(); 072 073 // ~ Instance fields 074 // ---------------------------------------------------------------------------- 075 076 /** The attributes list. */ 077 private Entry entry; 078 079 /** The current attribute being decoded */ 080 private EntryAttribute currentAttribute; 081 082 /** The add request length */ 083 private int addRequestLength; 084 085 /** The attributes length */ 086 private int attributesLength; 087 088 /** The list of all attributes length */ 089 private List<Integer> attributeLength; 090 091 /** The list of all vals length */ 092 private List<Integer> valuesLength; 093 094 095 // ~ Constructors 096 // ------------------------------------------------------------------------------- 097 098 /** 099 * Creates a new AddRequest object. 100 */ 101 public AddRequestCodec() 102 { 103 super(); 104 entry = new DefaultClientEntry(); 105 } 106 107 108 // ~ Methods 109 // ------------------------------------------------------------------------------------ 110 111 /** 112 * Get the message type 113 * 114 * @return Returns the type. 115 */ 116 public MessageTypeEnum getMessageType() 117 { 118 return MessageTypeEnum.ADD_REQUEST; 119 } 120 121 122 /** 123 * {@inheritDoc} 124 */ 125 public String getMessageTypeName() 126 { 127 return "ADD_REQUEST"; 128 } 129 130 131 /** 132 * Initialize the Entry. 133 */ 134 public void initEntry() 135 { 136 entry = new DefaultClientEntry(); 137 } 138 139 140 /** 141 * Get the entry to be added 142 * 143 * @return Returns the entry. 144 */ 145 public Entry getEntry() 146 { 147 return entry; 148 } 149 150 151 /** 152 * Sets the entry. 153 * 154 * @param entry 155 * the entry 156 */ 157 public void setEntry( Entry entry ) 158 { 159 this.entry = entry; 160 } 161 162 163 /** 164 * Create a new attributeValue 165 * 166 * @param type The attribute's name (called 'type' in the grammar) 167 */ 168 public void addAttributeType( String type ) throws LdapException 169 { 170 // do not create a new attribute if we have seen this attributeType before 171 if ( entry.get( type ) != null ) 172 { 173 currentAttribute = entry.get( type ); 174 return; 175 } 176 177 // fix this to use AttributeImpl(type.getString().toLowerCase()) 178 currentAttribute = new DefaultClientAttribute( type ); 179 entry.put( currentAttribute ); 180 } 181 182 183 /** 184 * Add a new value to the current attribute 185 * 186 * @param value The value to add 187 */ 188 public void addAttributeValue( String value ) 189 { 190 currentAttribute.add( value ); 191 } 192 193 194 /** 195 * Add a new value to the current attribute 196 * 197 * @param value The value to add 198 */ 199 public void addAttributeValue( org.apache.directory.shared.ldap.entry.Value<?> value ) 200 { 201 currentAttribute.add( value ); 202 } 203 204 205 /** 206 * Add a new value to the current attribute 207 * 208 * @param value The value to add 209 */ 210 public void addAttributeValue( byte[] value ) 211 { 212 currentAttribute.add( value ); 213 } 214 215 216 /** 217 * Get the added DN 218 * 219 * @return Returns the entry DN. 220 */ 221 public DN getEntryDn() 222 { 223 return entry.getDn(); 224 } 225 226 227 /** 228 * Set the added DN. 229 * 230 * @param entry The DN to set. 231 */ 232 public void setEntryDn( DN entryDn ) 233 { 234 entry.setDn( entryDn ); 235 } 236 237 238 /** 239 * Compute the AddRequest length 240 * 241 * AddRequest : 242 * 243 * 0x68 L1 244 * | 245 * +--> 0x04 L2 entry 246 * +--> 0x30 L3 (attributes) 247 * | 248 * +--> 0x30 L4-1 (attribute) 249 * | | 250 * | +--> 0x04 L5-1 type 251 * | +--> 0x31 L6-1 (values) 252 * | | 253 * | +--> 0x04 L7-1-1 value 254 * | +--> ... 255 * | +--> 0x04 L7-1-n value 256 * | 257 * +--> 0x30 L4-2 (attribute) 258 * | | 259 * | +--> 0x04 L5-2 type 260 * | +--> 0x31 L6-2 (values) 261 * | | 262 * | +--> 0x04 L7-2-1 value 263 * | +--> ... 264 * | +--> 0x04 L7-2-n value 265 * | 266 * +--> ... 267 * | 268 * +--> 0x30 L4-m (attribute) 269 * | 270 * +--> 0x04 L5-m type 271 * +--> 0x31 L6-m (values) 272 * | 273 * +--> 0x04 L7-m-1 value 274 * +--> ... 275 * +--> 0x04 L7-m-n value 276 */ 277 protected int computeLengthProtocolOp() 278 { 279 // The entry 280 addRequestLength = 1 + TLV.getNbBytes( DN.getNbBytes( entry.getDn() ) ) + DN.getNbBytes( entry.getDn() ); 281 282 // The attributes sequence 283 attributesLength = 0; 284 285 if ( ( entry != null ) && ( entry.size() != 0 ) ) 286 { 287 attributeLength = new LinkedList<Integer>(); 288 valuesLength = new LinkedList<Integer>(); 289 290 // Compute the attributes length 291 for ( EntryAttribute attribute : entry ) 292 { 293 int localAttributeLength = 0; 294 int localValuesLength = 0; 295 296 // Get the type length 297 int idLength = attribute.getId().getBytes().length; 298 localAttributeLength = 1 + TLV.getNbBytes( idLength ) + idLength; 299 300 // The values 301 if ( attribute.size() != 0 ) 302 { 303 localValuesLength = 0; 304 305 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute ) 306 { 307 int valueLength = value.getBytes().length; 308 localValuesLength += 1 + TLV.getNbBytes( valueLength ) + valueLength; 309 } 310 311 localAttributeLength += 1 + TLV.getNbBytes( localValuesLength ) + localValuesLength; 312 } 313 314 // add the attribute length to the attributes length 315 attributesLength += 1 + TLV.getNbBytes( localAttributeLength ) + localAttributeLength; 316 317 attributeLength.add( localAttributeLength ); 318 valuesLength.add( localValuesLength ); 319 } 320 } 321 322 addRequestLength += 1 + TLV.getNbBytes( attributesLength ) + attributesLength; 323 324 // Return the result. 325 int result = 1 + TLV.getNbBytes( addRequestLength ) + addRequestLength; 326 327 if ( IS_DEBUG ) 328 { 329 log.debug( "AddRequest PDU length = {}", Integer.valueOf( result ) ); 330 } 331 332 return result; 333 } 334 335 336 /** 337 * Encode the AddRequest message to a PDU. 338 * 339 * AddRequest : 340 * 341 * 0x68 LL 342 * 0x04 LL entry 343 * 0x30 LL attributesList 344 * 0x30 LL attributeList 345 * 0x04 LL attributeDescription 346 * 0x31 LL attributeValues 347 * 0x04 LL attributeValue 348 * ... 349 * 0x04 LL attributeValue 350 * ... 351 * 0x30 LL attributeList 352 * 0x04 LL attributeDescription 353 * 0x31 LL attributeValue 354 * 0x04 LL attributeValue 355 * ... 356 * 0x04 LL attributeValue 357 * 358 * @param buffer The buffer where to put the PDU 359 * @return The PDU. 360 */ 361 protected void encodeProtocolOp( ByteBuffer buffer ) throws EncoderException 362 { 363 try 364 { 365 // The AddRequest Tag 366 buffer.put( LdapConstants.ADD_REQUEST_TAG ); 367 buffer.put( TLV.getBytes( addRequestLength ) ); 368 369 // The entry 370 Value.encode( buffer, DN.getBytes( entry.getDn() ) ); 371 372 // The attributes sequence 373 buffer.put( UniversalTag.SEQUENCE_TAG ); 374 buffer.put( TLV.getBytes( attributesLength ) ); 375 376 // The partial attribute list 377 if ( ( entry != null ) && ( entry.size() != 0 ) ) 378 { 379 int attributeNumber = 0; 380 381 // Compute the attributes length 382 for ( EntryAttribute attribute : entry ) 383 { 384 // The attributes list sequence 385 buffer.put( UniversalTag.SEQUENCE_TAG ); 386 int localAttributeLength = attributeLength.get( attributeNumber ); 387 buffer.put( TLV.getBytes( localAttributeLength ) ); 388 389 // The attribute type 390 Value.encode( buffer, attribute.getId() ); 391 392 // The values 393 buffer.put( UniversalTag.SET_TAG ); 394 int localValuesLength = valuesLength.get( attributeNumber ); 395 buffer.put( TLV.getBytes( localValuesLength ) ); 396 397 if ( attribute.size() != 0 ) 398 { 399 for ( org.apache.directory.shared.ldap.entry.Value<?> value : attribute ) 400 { 401 if ( value.isBinary() ) 402 { 403 Value.encode( buffer, value.getBytes() ); 404 } 405 else 406 { 407 Value.encode( buffer, value.getString() ); 408 } 409 } 410 } 411 412 // Go to the next attribute number; 413 attributeNumber++; 414 } 415 } 416 } 417 catch ( BufferOverflowException boe ) 418 { 419 throw new EncoderException( "The PDU buffer size is too small !" ); 420 } 421 422 if ( IS_DEBUG ) 423 { 424 log.debug( "AddRequest encoding : {}", StringTools.dumpBytes( buffer.array() ) ); 425 log.debug( "AddRequest initial value : {}", toString() ); 426 } 427 } 428 429 430 /** 431 * @return Returns the currentAttribute type. 432 */ 433 public String getCurrentAttributeType() 434 { 435 return currentAttribute.getId(); 436 } 437 438 439 /** 440 * Return a String representing an AddRequest 441 * 442 * @return A String representing the AddRequest 443 */ 444 public String toString() 445 { 446 StringBuilder sb = new StringBuilder(); 447 448 sb.append( " Add Request\n" ); 449 sb.append( " Attributes\n" ); 450 451 if ( entry == null ) 452 { 453 sb.append( " No attributes" ); 454 } 455 else 456 { 457 sb.append( entry ); 458 } 459 460 return toString( sb.toString() ); 461 } 462 }